mcpill 1.2.1 → 1.2.3

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/CHANGELOG.md CHANGED
@@ -1,5 +1,16 @@
1
1
  # Changelog
2
2
 
3
+ ## 1.2.3
4
+
5
+ - `mcpill init` now scaffolds a `package.json` with `type: module` and `mcpill-runtime` as the only dependency; prints `Run: npm install` rather than auto-installing
6
+ - `mcpill run` and `mcpill validate` now catch missing `mcpill-runtime` import errors and surface an actionable message
7
+ - Removed stale `echo`/`greet` tool examples from the default scaffold; replaced with a single `my-tool` placeholder — examples moved to `pill-user-guide.md`
8
+ - `mcpill compile` parses `PILL.md` `## Server` block and lets it win over `server.md` for `name`/`transport`; both files coexist with different roles — `server.md` is editable directly, `PILL.md` is the intent-level spec for the agent
9
+
10
+ ## 1.2.2
11
+
12
+ - Fix: bump mcpster dependency to `^0.3.0` — `0.2.x` did not export `applySetup`, causing a crash on `mcpill --version` after global install
13
+
3
14
  ## 1.2.1
4
15
 
5
16
  - All init assets scoped under `.mcpill/` — only `PILL.md` is written to the project root
package/README.md CHANGED
@@ -42,13 +42,12 @@ mcpill run # start the server
42
42
 
43
43
  Scaffolds a new project in the current directory:
44
44
 
45
- - `README.md` — quickstart guide for the scaffolded project
46
45
  - `PILL.md` — intent-level spec; fill this and hand to Claude to generate source files
47
- - `pill-agent-guide.md` — agent instructions read by Claude when building from `PILL.md`
48
- - `server.md` — server config + resources
49
- - `tools/echo.md` — example tool
50
- - `prompts/greeting.md` — example prompt
51
- - `package.json` — with `pack` and `publish` scripts ready
46
+ - `.mcpill/pill-agent-guide.md` — agent instructions read by Claude when building from `PILL.md`
47
+ - `.mcpill/server.md` — server config + resources
48
+ - `.mcpill/server/prompts/greeting.md` — example prompt
49
+ - `.mcpill/HELLO-MCP.md` — ready-to-run example (copy into `PILL.md` to try it)
50
+ - `package.json` — `{ type: "module", dependencies: { mcpill-runtime } }` run `npm install`
52
51
 
53
52
  ### `mcpill compile`
54
53
 
package/dist/cli.js CHANGED
@@ -127,25 +127,14 @@ transport: stdio
127
127
 
128
128
  ---
129
129
 
130
- ## Tool: echo
130
+ ## Tool: my-tool
131
131
 
132
- description: Echo a message back to the caller.
132
+ description: Describe what this tool does.
133
133
  inputs:
134
- - message (string): The message to echo.
135
- output: The same message, echoed back as text.
134
+ - param (string): A parameter.
135
+ output: What the tool returns.
136
136
  behavior: |
137
- Return the message input unchanged.
138
-
139
- ---
140
-
141
- ## Tool: greet
142
-
143
- description: Generate a personalised greeting.
144
- inputs:
145
- - name (string): The name of the person to greet.
146
- output: A greeting string addressed to the given name.
147
- behavior: |
148
- Return "Hello, {name}!" as a text response.
137
+ Describe the logic here. Claude will implement it.
149
138
 
150
139
  ---
151
140
 
@@ -234,22 +223,6 @@ name: Status
234
223
  ---
235
224
  The server is running.
236
225
  `;
237
- var ECHO_TOOL_MD = `# echo
238
-
239
- Echo a message back
240
-
241
- ## Parameters
242
-
243
- - message (string): The message to echo
244
-
245
- ## Handler
246
-
247
- \`\`\`js
248
- async ({ message }) => {
249
- return { content: [{ type: "text", text: message }] };
250
- }
251
- \`\`\`
252
- `;
253
226
  var GREETING_PROMPT_MD = `# greeting
254
227
 
255
228
  Generate a greeting
@@ -298,7 +271,7 @@ ${projectName}/
298
271
  \u2514\u2500\u2500 server/
299
272
  \u251C\u2500\u2500 mcpill.config.json \u2190 compiled config
300
273
  \u251C\u2500\u2500 tools/ \u2190 one .md file per tool
301
- \u2502 \u2514\u2500\u2500 echo.md
274
+ \u2502 \u2514\u2500\u2500 my-tool.md
302
275
  \u2514\u2500\u2500 prompts/ \u2190 one .md file per prompt (optional)
303
276
  \u2514\u2500\u2500 greeting.md
304
277
  \`\`\`
@@ -341,7 +314,6 @@ async function runInit(opts) {
341
314
  fs.mkdirSync(path.join(serverDir, "prompts"), { recursive: true });
342
315
  const serverMd = SERVER_MD_TEMPLATE.replace("name: my-server", `name: ${projectName}`);
343
316
  fs.writeFileSync(path.join(mcpillDir, "server.md"), serverMd);
344
- fs.writeFileSync(path.join(serverDir, "tools", "echo.md"), ECHO_TOOL_MD);
345
317
  fs.writeFileSync(path.join(serverDir, "prompts", "greeting.md"), GREETING_PROMPT_MD);
346
318
  fs.writeFileSync(
347
319
  path.join(serverDir, "mcpill.config.json"),
@@ -351,15 +323,27 @@ async function runInit(opts) {
351
323
  fs.writeFileSync(path.join(mcpillDir, "pill-user-guide.md"), makePillUserGuideMd(projectName));
352
324
  fs.writeFileSync(path.join(mcpillDir, "HELLO-MCP.md"), HELLO_MCP_MD);
353
325
  fs.writeFileSync(path.join(targetDir, "PILL.md"), makePillMd(projectName));
326
+ const pkgJsonPath = path.join(targetDir, "package.json");
327
+ if (!fs.existsSync(pkgJsonPath)) {
328
+ const pkg2 = {
329
+ name: projectName,
330
+ version: "0.1.0",
331
+ type: "module",
332
+ dependencies: {
333
+ "mcpill-runtime": "latest"
334
+ }
335
+ };
336
+ fs.writeFileSync(pkgJsonPath, JSON.stringify(pkg2, null, 2) + "\n");
337
+ }
354
338
  console.log('\u2713 PILL.md \u2190 describe your server, then tell Claude: "Build this PILL.md"');
339
+ console.log("\u2713 package.json \u2190 Run: npm install");
355
340
  console.log("\u2713 .mcpill/HELLO-MCP.md \u2190 copy into PILL.md to see a working example instantly");
356
341
  console.log("\u2713 .mcpill/server.md \u2190 or edit source files directly");
357
- console.log("\u2713 .mcpill/server/tools/echo.md");
358
342
  console.log("\u2713 .mcpill/server/prompts/greeting.md");
359
343
  console.log("\u2713 .mcpill/pill-agent-guide.md \u2190 agent instructions (read by Claude)");
360
344
  console.log("\u2713 .mcpill/pill-user-guide.md \u2190 start here");
361
345
  console.log("");
362
- console.log("When ready: mcpill compile && mcpill run");
346
+ console.log("Next: npm install && mcpill compile && mcpill run");
363
347
  }
364
348
 
365
349
  // src/commands/run.ts
@@ -397,6 +381,11 @@ async function loadTools(mcpillDir) {
397
381
  mod = await import(pathToFileURL(toolsPath).href);
398
382
  } catch (err) {
399
383
  const msg = err instanceof Error ? err.message : String(err);
384
+ if (msg.includes("mcpill-runtime")) {
385
+ throw new Error(
386
+ "tools.js failed to load: mcpill-runtime not found.\nRun: npm install mcpill-runtime"
387
+ );
388
+ }
400
389
  throw new Error(`tools.js failed to load: ${msg}`);
401
390
  }
402
391
  const tools = mod.default;
@@ -1083,6 +1072,18 @@ async function runCompile(opts) {
1083
1072
  const toolsJsPath = join3(serverDir, "tools.js");
1084
1073
  const existing = existsSync(toolsJsPath) ? extractHandlers(readFileSync2(toolsJsPath, "utf-8")) : /* @__PURE__ */ new Map();
1085
1074
  const { doc: mergedDoc, stubbed } = mergeHandlers(doc, existing);
1075
+ const pillMdPath = join3(baseDir, "PILL.md");
1076
+ if (existsSync(pillMdPath)) {
1077
+ const pillContent = readFileSync2(pillMdPath, "utf-8");
1078
+ const serverSection = ("\n" + pillContent).split("\n## ").find((s) => s.startsWith("Server\n"));
1079
+ if (serverSection) {
1080
+ const kv = parseKvBlock(serverSection.slice("Server\n".length));
1081
+ if (kv["name"]) mergedDoc.config.name = kv["name"];
1082
+ if (kv["transport"] === "stdio" || kv["transport"] === "http") {
1083
+ mergedDoc.config.transport = kv["transport"];
1084
+ }
1085
+ }
1086
+ }
1086
1087
  if (opts.strict && stubbed.length > 0) {
1087
1088
  throw new Error("Missing handlers for: " + stubbed.join(", "));
1088
1089
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "mcpill",
3
- "version": "1.2.1",
3
+ "version": "1.2.3",
4
4
  "type": "module",
5
5
  "description": "CLI for building, validating, and publishing MCP servers using the pill format.",
6
6
  "homepage": "https://mcpill.ruco.dev",
@@ -22,7 +22,7 @@
22
22
  },
23
23
  "dependencies": {
24
24
  "mcpill-runtime": "^0.1.0",
25
- "mcpster": "^0.2.5",
25
+ "mcpster": "^0.3.0",
26
26
  "commander": "^12"
27
27
  },
28
28
  "devDependencies": {
@@ -1,7 +1,7 @@
1
1
  import { resolve, join } from 'path';
2
2
  import { readFileSync, writeFileSync, mkdirSync, existsSync } from 'fs';
3
3
  import { pathToFileURL } from 'url';
4
- import { parseServerDir } from '../compiler/parse.js';
4
+ import { parseServerDir, parseKvBlock } from '../compiler/parse.js';
5
5
  import { serializeServerDir } from '../compiler/serialize.js';
6
6
  import { extractHandlers, mergeHandlers } from '../compiler/merge-tools.js';
7
7
  import { loadConfig } from '../loaders/config.js';
@@ -134,6 +134,21 @@ export async function runCompile(opts: {
134
134
 
135
135
  const { doc: mergedDoc, stubbed } = mergeHandlers(doc, existing);
136
136
 
137
+ // If PILL.md declares a name/transport in its ## Server section, let it win
138
+ // over whatever server.md still has (catches cases where the agent forgets to update server.md).
139
+ const pillMdPath = join(baseDir, 'PILL.md');
140
+ if (existsSync(pillMdPath)) {
141
+ const pillContent = readFileSync(pillMdPath, 'utf-8');
142
+ const serverSection = ('\n' + pillContent).split('\n## ').find((s) => s.startsWith('Server\n'));
143
+ if (serverSection) {
144
+ const kv = parseKvBlock(serverSection.slice('Server\n'.length));
145
+ if (kv['name']) mergedDoc.config.name = kv['name'];
146
+ if (kv['transport'] === 'stdio' || kv['transport'] === 'http') {
147
+ mergedDoc.config.transport = kv['transport'];
148
+ }
149
+ }
150
+ }
151
+
137
152
  if (opts.strict && stubbed.length > 0) {
138
153
  throw new Error('Missing handlers for: ' + stubbed.join(', '));
139
154
  }
@@ -120,25 +120,14 @@ transport: stdio
120
120
 
121
121
  ---
122
122
 
123
- ## Tool: echo
124
-
125
- description: Echo a message back to the caller.
126
- inputs:
127
- - message (string): The message to echo.
128
- output: The same message, echoed back as text.
129
- behavior: |
130
- Return the message input unchanged.
131
-
132
- ---
123
+ ## Tool: my-tool
133
124
 
134
- ## Tool: greet
135
-
136
- description: Generate a personalised greeting.
125
+ description: Describe what this tool does.
137
126
  inputs:
138
- - name (string): The name of the person to greet.
139
- output: A greeting string addressed to the given name.
127
+ - param (string): A parameter.
128
+ output: What the tool returns.
140
129
  behavior: |
141
- Return "Hello, {name}!" as a text response.
130
+ Describe the logic here. Claude will implement it.
142
131
 
143
132
  ---
144
133
 
@@ -232,23 +221,6 @@ name: Status
232
221
  The server is running.
233
222
  `;
234
223
 
235
- const ECHO_TOOL_MD = `# echo
236
-
237
- Echo a message back
238
-
239
- ## Parameters
240
-
241
- - message (string): The message to echo
242
-
243
- ## Handler
244
-
245
- \`\`\`js
246
- async ({ message }) => {
247
- return { content: [{ type: "text", text: message }] };
248
- }
249
- \`\`\`
250
- `;
251
-
252
224
  const GREETING_PROMPT_MD = `# greeting
253
225
 
254
226
  Generate a greeting
@@ -298,7 +270,7 @@ ${projectName}/
298
270
  └── server/
299
271
  ├── mcpill.config.json ← compiled config
300
272
  ├── tools/ ← one .md file per tool
301
- │ └── echo.md
273
+ │ └── my-tool.md
302
274
  └── prompts/ ← one .md file per prompt (optional)
303
275
  └── greeting.md
304
276
  \`\`\`
@@ -345,7 +317,6 @@ export async function runInit(opts: { dir?: string }): Promise<void> {
345
317
 
346
318
  const serverMd = SERVER_MD_TEMPLATE.replace("name: my-server", `name: ${projectName}`);
347
319
  fs.writeFileSync(path.join(mcpillDir, "server.md"), serverMd);
348
- fs.writeFileSync(path.join(serverDir, "tools", "echo.md"), ECHO_TOOL_MD);
349
320
  fs.writeFileSync(path.join(serverDir, "prompts", "greeting.md"), GREETING_PROMPT_MD);
350
321
  fs.writeFileSync(
351
322
  path.join(serverDir, "mcpill.config.json"),
@@ -357,13 +328,26 @@ export async function runInit(opts: { dir?: string }): Promise<void> {
357
328
 
358
329
  fs.writeFileSync(path.join(targetDir, "PILL.md"), makePillMd(projectName));
359
330
 
331
+ const pkgJsonPath = path.join(targetDir, "package.json");
332
+ if (!fs.existsSync(pkgJsonPath)) {
333
+ const pkg = {
334
+ name: projectName,
335
+ version: "0.1.0",
336
+ type: "module",
337
+ dependencies: {
338
+ "mcpill-runtime": "latest",
339
+ },
340
+ };
341
+ fs.writeFileSync(pkgJsonPath, JSON.stringify(pkg, null, 2) + "\n");
342
+ }
343
+
360
344
  console.log("✓ PILL.md ← describe your server, then tell Claude: \"Build this PILL.md\"");
345
+ console.log("✓ package.json ← Run: npm install");
361
346
  console.log("✓ .mcpill/HELLO-MCP.md ← copy into PILL.md to see a working example instantly");
362
347
  console.log("✓ .mcpill/server.md ← or edit source files directly");
363
- console.log("✓ .mcpill/server/tools/echo.md");
364
348
  console.log("✓ .mcpill/server/prompts/greeting.md");
365
349
  console.log("✓ .mcpill/pill-agent-guide.md ← agent instructions (read by Claude)");
366
350
  console.log("✓ .mcpill/pill-user-guide.md ← start here");
367
351
  console.log("");
368
- console.log("When ready: mcpill compile && mcpill run");
352
+ console.log("Next: npm install && mcpill compile && mcpill run");
369
353
  }
@@ -16,6 +16,11 @@ export async function loadTools(mcpillDir: string): Promise<RawToolDef[]> {
16
16
  mod = await import(pathToFileURL(toolsPath).href);
17
17
  } catch (err) {
18
18
  const msg = err instanceof Error ? err.message : String(err);
19
+ if (msg.includes("mcpill-runtime")) {
20
+ throw new Error(
21
+ "tools.js failed to load: mcpill-runtime not found.\nRun: npm install mcpill-runtime"
22
+ );
23
+ }
19
24
  throw new Error(`tools.js failed to load: ${msg}`);
20
25
  }
21
26