par5-mcp 0.1.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.
@@ -1,3 +1,3 @@
1
1
  {
2
- ".": "0.1.0"
2
+ ".": "0.1.1"
3
3
  }
package/CHANGELOG.md CHANGED
@@ -1,5 +1,12 @@
1
1
  # Changelog
2
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
+
3
10
  ## 0.1.0 (2025-12-30)
4
11
 
5
12
 
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 = randomUUID();
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,6 +1,6 @@
1
1
  {
2
2
  "name": "par5-mcp",
3
- "version": "0.1.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": {
@@ -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": {