par5-mcp 0.0.0 → 0.1.1
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/.github/workflows/publish.yml +2 -6
- package/.release-please-manifest.json +1 -1
- package/CHANGELOG.md +15 -0
- package/dist/index.js +104 -1
- package/package.json +4 -2
|
@@ -6,6 +6,7 @@ on:
|
|
|
6
6
|
- main
|
|
7
7
|
|
|
8
8
|
permissions:
|
|
9
|
+
id-token: write
|
|
9
10
|
contents: write
|
|
10
11
|
pull-requests: write
|
|
11
12
|
|
|
@@ -29,13 +30,8 @@ jobs:
|
|
|
29
30
|
|
|
30
31
|
- uses: actions/setup-node@v4
|
|
31
32
|
with:
|
|
32
|
-
node-version: '
|
|
33
|
+
node-version: '22'
|
|
33
34
|
registry-url: 'https://registry.npmjs.org'
|
|
34
|
-
|
|
35
35
|
- run: npm ci
|
|
36
|
-
|
|
37
36
|
- run: npm run build
|
|
38
|
-
|
|
39
37
|
- run: npm publish
|
|
40
|
-
env:
|
|
41
|
-
NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }}
|
package/CHANGELOG.md
ADDED
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
# Changelog
|
|
2
|
+
|
|
3
|
+
## [0.1.1](https://github.com/jrandolf/par5-mcp/compare/v0.1.0...v0.1.1) (2025-12-30)
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
### Features
|
|
7
|
+
|
|
8
|
+
* implement diceware list names and create_list_from_shell ([5e3e0ff](https://github.com/jrandolf/par5-mcp/commit/5e3e0ff9cbdce32a7d399f9eea8a7bd36b7d876f))
|
|
9
|
+
|
|
10
|
+
## 0.1.0 (2025-12-30)
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
### Features
|
|
14
|
+
|
|
15
|
+
* initial commit ([4f95cea](https://github.com/jrandolf/par5-mcp/commit/4f95ceaf254e9667103673e34d87dd84a8a09693))
|
package/dist/index.js
CHANGED
|
@@ -6,6 +6,7 @@ import { tmpdir } from "node:os";
|
|
|
6
6
|
import { basename, join } from "node:path";
|
|
7
7
|
import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
|
|
8
8
|
import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
|
|
9
|
+
import generatePassphrase from "eff-diceware-passphrase";
|
|
9
10
|
import { z } from "zod";
|
|
10
11
|
// Helper to create a safe filename from an item string
|
|
11
12
|
function toSafeFilename(item) {
|
|
@@ -71,6 +72,17 @@ async function runInBatches(tasks) {
|
|
|
71
72
|
const outputDir = join(tmpdir(), "par5-mcp-results");
|
|
72
73
|
// Store for lists
|
|
73
74
|
const lists = new Map();
|
|
75
|
+
// Generate a unique diceware list ID (3 words joined with hyphens)
|
|
76
|
+
function generateListId() {
|
|
77
|
+
const words = generatePassphrase(3);
|
|
78
|
+
let id = words.join("-");
|
|
79
|
+
// Ensure uniqueness by appending more words if needed
|
|
80
|
+
while (lists.has(id)) {
|
|
81
|
+
const extraWord = generatePassphrase(1)[0];
|
|
82
|
+
id = `${id}-${extraWord}`;
|
|
83
|
+
}
|
|
84
|
+
return id;
|
|
85
|
+
}
|
|
74
86
|
// Create the MCP server
|
|
75
87
|
const server = new McpServer({
|
|
76
88
|
name: "par5-mcp",
|
|
@@ -96,7 +108,7 @@ EXAMPLE: To process files ["src/a.ts", "src/b.ts", "src/c.ts"], first create a l
|
|
|
96
108
|
.describe("Array of items to store in the list. Each item can be a file path, URL, identifier, or any string that will be substituted into commands or prompts."),
|
|
97
109
|
},
|
|
98
110
|
}, async ({ items }) => {
|
|
99
|
-
const id =
|
|
111
|
+
const id = generateListId();
|
|
100
112
|
lists.set(id, items);
|
|
101
113
|
return {
|
|
102
114
|
content: [
|
|
@@ -107,6 +119,97 @@ EXAMPLE: To process files ["src/a.ts", "src/b.ts", "src/c.ts"], first create a l
|
|
|
107
119
|
],
|
|
108
120
|
};
|
|
109
121
|
});
|
|
122
|
+
// Tool: create_list_from_shell
|
|
123
|
+
server.registerTool("create_list_from_shell", {
|
|
124
|
+
description: `Creates a list by running a shell command and parsing its newline-delimited output.
|
|
125
|
+
|
|
126
|
+
WHEN TO USE:
|
|
127
|
+
- When you need to create a list from command output (e.g., find, ls, grep, git ls-files)
|
|
128
|
+
- When the list of items to process is determined by a shell command
|
|
129
|
+
- As an alternative to manually specifying items in create_list
|
|
130
|
+
|
|
131
|
+
EXAMPLES:
|
|
132
|
+
- "find src -name '*.ts'" to get all TypeScript files
|
|
133
|
+
- "git ls-files '*.tsx'" to get all tracked TSX files
|
|
134
|
+
- "ls *.json" to get all JSON files in current directory
|
|
135
|
+
- "grep -l 'TODO' src/**/*.ts" to get files containing TODO
|
|
136
|
+
|
|
137
|
+
WORKFLOW:
|
|
138
|
+
1. Call create_list_from_shell with your command
|
|
139
|
+
2. The command's stdout is split by newlines to create list items
|
|
140
|
+
3. Empty lines are filtered out
|
|
141
|
+
4. Use the returned list_id with run_shell_across_list or run_agent_across_list`,
|
|
142
|
+
inputSchema: {
|
|
143
|
+
command: z
|
|
144
|
+
.string()
|
|
145
|
+
.describe("Shell command to run. Its stdout will be split by newlines to create list items. Example: 'find src -name \"*.ts\"' or 'git ls-files'"),
|
|
146
|
+
},
|
|
147
|
+
}, async ({ command }) => {
|
|
148
|
+
return new Promise((resolve) => {
|
|
149
|
+
const child = spawn("sh", ["-c", command], {
|
|
150
|
+
stdio: ["ignore", "pipe", "pipe"],
|
|
151
|
+
});
|
|
152
|
+
let stdout = "";
|
|
153
|
+
let stderr = "";
|
|
154
|
+
child.stdout.on("data", (data) => {
|
|
155
|
+
stdout += data.toString();
|
|
156
|
+
});
|
|
157
|
+
child.stderr.on("data", (data) => {
|
|
158
|
+
stderr += data.toString();
|
|
159
|
+
});
|
|
160
|
+
child.on("close", (code) => {
|
|
161
|
+
if (code !== 0 && stderr) {
|
|
162
|
+
resolve({
|
|
163
|
+
content: [
|
|
164
|
+
{
|
|
165
|
+
type: "text",
|
|
166
|
+
text: `Error: Command exited with code ${code}.\n\nstderr:\n${stderr}`,
|
|
167
|
+
},
|
|
168
|
+
],
|
|
169
|
+
isError: true,
|
|
170
|
+
});
|
|
171
|
+
return;
|
|
172
|
+
}
|
|
173
|
+
// Split by newlines and filter out empty lines
|
|
174
|
+
const items = stdout
|
|
175
|
+
.split("\n")
|
|
176
|
+
.map((line) => line.trim())
|
|
177
|
+
.filter((line) => line.length > 0);
|
|
178
|
+
if (items.length === 0) {
|
|
179
|
+
resolve({
|
|
180
|
+
content: [
|
|
181
|
+
{
|
|
182
|
+
type: "text",
|
|
183
|
+
text: `Warning: Command produced no output. No list was created.${stderr ? `\n\nstderr:\n${stderr}` : ""}`,
|
|
184
|
+
},
|
|
185
|
+
],
|
|
186
|
+
});
|
|
187
|
+
return;
|
|
188
|
+
}
|
|
189
|
+
const id = generateListId();
|
|
190
|
+
lists.set(id, items);
|
|
191
|
+
resolve({
|
|
192
|
+
content: [
|
|
193
|
+
{
|
|
194
|
+
type: "text",
|
|
195
|
+
text: `Successfully created a list with ${items.length} items from command output. The list ID is "${id}". You can now use this ID with run_shell_across_list or run_agent_across_list to process each item in parallel.${stderr ? `\n\nNote: Command produced stderr output:\n${stderr}` : ""}`,
|
|
196
|
+
},
|
|
197
|
+
],
|
|
198
|
+
});
|
|
199
|
+
});
|
|
200
|
+
child.on("error", (err) => {
|
|
201
|
+
resolve({
|
|
202
|
+
content: [
|
|
203
|
+
{
|
|
204
|
+
type: "text",
|
|
205
|
+
text: `Error: Failed to execute command: ${err.message}`,
|
|
206
|
+
},
|
|
207
|
+
],
|
|
208
|
+
isError: true,
|
|
209
|
+
});
|
|
210
|
+
});
|
|
211
|
+
});
|
|
212
|
+
});
|
|
110
213
|
// Tool: get_list
|
|
111
214
|
server.registerTool("get_list", {
|
|
112
215
|
description: `Retrieves the items in an existing list by its ID.
|
package/package.json
CHANGED
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "par5-mcp",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.1.1",
|
|
4
4
|
"description": "MCP server for parallel list operations - run shell commands and AI agents across lists in parallel",
|
|
5
5
|
"main": "dist/index.js",
|
|
6
6
|
"bin": {
|
|
7
|
-
"par5-mcp": "
|
|
7
|
+
"par5-mcp": "dist/index.js"
|
|
8
8
|
},
|
|
9
9
|
"scripts": {
|
|
10
10
|
"build": "tsc",
|
|
@@ -39,6 +39,8 @@
|
|
|
39
39
|
"type": "module",
|
|
40
40
|
"dependencies": {
|
|
41
41
|
"@modelcontextprotocol/sdk": "^1.25.1",
|
|
42
|
+
"@types/eff-diceware-passphrase": "^3.0.2",
|
|
43
|
+
"eff-diceware-passphrase": "^3.0.0",
|
|
42
44
|
"zod": "^4.2.1"
|
|
43
45
|
},
|
|
44
46
|
"devDependencies": {
|