mcpill 1.6.0 → 1.7.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/CHANGELOG.md CHANGED
@@ -1,5 +1,11 @@
1
1
  # Changelog
2
2
 
3
+ ## 1.7.0
4
+
5
+ - `mcpill run` is now side-effect-free by default — stopping the process disconnects the server; no Claude config is written
6
+ - `mcpill run --register` retains the old persistent behavior: registers the server entry in Claude config so Claude manages the process
7
+ - `mcpill unregister` removes the server entry from `.claude/settings.json`, `~/.claude.json`, and Claude Desktop config
8
+
3
9
  ## 1.6.0
4
10
 
5
11
  - `HELLO-MCP.md` template (scaffolded by `mcpill init`) now includes a commented-out `## Hook:` section stub with inline field explanations for all four Claude Code event types
package/README.md CHANGED
@@ -20,7 +20,8 @@ Describe your server in plain English, let Claude generate the source files.
20
20
  mcpill init # scaffolds PILL.md + example source files
21
21
  # fill PILL.md # describe your server: tools, resources, prompts
22
22
  # tell Claude: "Build this PILL.md" # agent generates source files + runs compile
23
- mcpill run # start the server
23
+ mcpill run # start the server (transient — stops when you do)
24
+ mcpill run --register # or: register so Claude manages it persistently
24
25
  ```
25
26
 
26
27
  `PILL.md` embeds the agent instructions — Claude knows exactly what to generate and how.
@@ -31,7 +32,7 @@ mcpill run # start the server
31
32
  mcpill init # scaffolds server.md + tools/ + prompts/
32
33
  # edit source files # tools/*.md, prompts/*.md, server.md
33
34
  mcpill compile # compile source → .{name}/ pill artifact
34
- mcpill run # start the server
35
+ mcpill run # start the server (transient — stops when you do)
35
36
  ```
36
37
 
37
38
  ---
@@ -89,8 +90,22 @@ Starts the MCP server from the pill artifact.
89
90
  ```bash
90
91
  mcpill run # stdio (default)
91
92
  mcpill run --transport http --port 3333
93
+ mcpill run --register # also write server entry to Claude config
92
94
  ```
93
95
 
96
+ `--register` is opt-in. Without it, running the server has no side effects on Claude's configuration — stopping the process fully disconnects it.
97
+
98
+ ### `mcpill unregister`
99
+
100
+ Removes the server entry from all Claude config files — the inverse of `mcpill run --register`.
101
+
102
+ ```bash
103
+ mcpill unregister
104
+ mcpill unregister --dir <path>
105
+ ```
106
+
107
+ Removes from `.claude/settings.json` (project scope), `~/.claude.json` (user scope), and the Claude Desktop config. Prints what was removed, or reports if the server was not registered.
108
+
94
109
  ### `mcpill pack`
95
110
 
96
111
  Prepares the pill for npm distribution:
package/dist/cli.js CHANGED
@@ -1157,15 +1157,17 @@ async function runServer(opts) {
1157
1157
  resolver: async () => content
1158
1158
  });
1159
1159
  }
1160
- applySetup(name, tools.map((t) => t.name), {
1161
- projectPath: baseDir,
1162
- permissions: "restrictive",
1163
- register: true,
1164
- cmdOverride: {
1165
- command: "mcpill",
1166
- args: ["run", "--dir", baseDir]
1167
- }
1168
- });
1160
+ if (opts.register) {
1161
+ applySetup(name, tools.map((t) => t.name), {
1162
+ projectPath: baseDir,
1163
+ permissions: "restrictive",
1164
+ register: true,
1165
+ cmdOverride: {
1166
+ command: "mcpill",
1167
+ args: ["run", "--dir", baseDir]
1168
+ }
1169
+ });
1170
+ }
1169
1171
  try {
1170
1172
  await server.start();
1171
1173
  } catch (err) {
@@ -1559,6 +1561,72 @@ async function runPublish(dir, access) {
1559
1561
  }
1560
1562
  }
1561
1563
 
1564
+ // src/commands/unregister.ts
1565
+ import path10 from "path";
1566
+ import fs8 from "fs";
1567
+ import os from "os";
1568
+ function patchJson(filePath, patcher) {
1569
+ if (!fs8.existsSync(filePath)) return false;
1570
+ try {
1571
+ const obj = JSON.parse(fs8.readFileSync(filePath, "utf-8"));
1572
+ patcher(obj);
1573
+ fs8.writeFileSync(filePath, JSON.stringify(obj, null, 2) + "\n", "utf-8");
1574
+ return true;
1575
+ } catch {
1576
+ return false;
1577
+ }
1578
+ }
1579
+ function desktopConfigPaths() {
1580
+ const home = os.homedir();
1581
+ if (process.platform === "win32") {
1582
+ const appData = process.env.APPDATA ?? path10.join(home, "AppData", "Roaming");
1583
+ return [path10.join(appData, "Claude", "claude_desktop_config.json")];
1584
+ }
1585
+ return [path10.join(home, "Library", "Application Support", "Claude", "claude_desktop_config.json")];
1586
+ }
1587
+ async function runUnregister(opts) {
1588
+ const baseDir = path10.resolve(opts.dir ?? process.cwd());
1589
+ const mcpillDir = path10.join(baseDir, ".mcpill", "server");
1590
+ const config = await loadConfig(mcpillDir);
1591
+ const { name } = config;
1592
+ let removed = 0;
1593
+ const settingsPath = path10.join(baseDir, ".claude", "settings.json");
1594
+ const removedProject = patchJson(settingsPath, (obj) => {
1595
+ const servers = obj.mcpServers;
1596
+ if (servers && name in servers) {
1597
+ delete servers[name];
1598
+ removed++;
1599
+ }
1600
+ });
1601
+ if (removedProject) process.stderr.write(`removed "${name}" from .claude/settings.json
1602
+ `);
1603
+ const claudeJsonPath = path10.join(os.homedir(), ".claude.json");
1604
+ const removedUser = patchJson(claudeJsonPath, (obj) => {
1605
+ const servers = obj.mcpServers;
1606
+ if (servers && name in servers) {
1607
+ delete servers[name];
1608
+ removed++;
1609
+ }
1610
+ });
1611
+ if (removedUser) process.stderr.write(`removed "${name}" from ~/.claude.json
1612
+ `);
1613
+ for (const configPath of desktopConfigPaths()) {
1614
+ const removedDesktop = patchJson(configPath, (obj) => {
1615
+ const servers = obj.mcpServers;
1616
+ if (servers && name in servers) {
1617
+ delete servers[name];
1618
+ removed++;
1619
+ }
1620
+ });
1621
+ if (removedDesktop) process.stderr.write(`removed "${name}" from Claude Desktop config
1622
+ `);
1623
+ }
1624
+ if (removed === 0) {
1625
+ process.stderr.write(`"${name}" was not registered \u2014 nothing to remove
1626
+ `);
1627
+ }
1628
+ }
1629
+
1562
1630
  // src/cli.ts
1563
1631
  var pkgDir = dirname(fileURLToPath(import.meta.url));
1564
1632
  var pkg = JSON.parse(
@@ -1569,7 +1637,7 @@ program.name("mcpill").version(pkg.version);
1569
1637
  program.command("init").description("Scaffold a new .mcpill/ directory").option("--dir <path>", "Target directory").action(async (opts) => {
1570
1638
  await runInit(opts);
1571
1639
  });
1572
- program.command("run").description("Start the MCP server").option("--transport <transport>", "Transport type: stdio or http").option("--port <n>", "Port number (HTTP only)", parseInt).option("--dir <path>", "Directory containing .mcpill/").action(
1640
+ program.command("run").description("Start the MCP server").option("--transport <type>", "Transport: stdio (default) or http").option("--port <n>", "Port number (HTTP only)", parseInt).option("--dir <path>", "Project root containing .mcpill/").option("--register", "Write server entry to Claude config so Claude manages the process").action(
1573
1641
  async (opts) => {
1574
1642
  await runServer(opts);
1575
1643
  }
@@ -1581,6 +1649,9 @@ program.command("validate").description("Validate .mcpill/ configuration").optio
1581
1649
  program.command("compile").description("Compile server.md \u2194 .mcpill/ files").option("--dir <path>", "Directory containing server.md and .mcpill/").option("--to-md", "Reverse: generate server.md from .mcpill/ files").option("--strict", "Error on missing tool handlers instead of generating stubs").option("--no-hooks", "Skip writing the PreToolUse hook to .claude/settings.json").action(async (opts) => {
1582
1650
  await runCompile({ ...opts, noHooks: opts.hooks === false });
1583
1651
  });
1652
+ program.command("unregister").description("Remove server entry from Claude config (undo mcpill run --register)").option("--dir <path>", "Project root containing .mcpill/").action(async (opts) => {
1653
+ await runUnregister(opts);
1654
+ });
1584
1655
  program.command("pack").description("Prepare pill for npm distribution").option("--dir <path>", "pill project root", ".").action(({ dir }) => runPack(dir));
1585
1656
  program.command("publish").description("Pack and publish pill to npm").option("--dir <path>", "pill project root", ".").option("--access <level>", "npm access level", "public").action(({ dir, access }) => runPublish(dir, access));
1586
1657
  program.parseAsync(process.argv).catch((err) => {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "mcpill",
3
- "version": "1.6.0",
3
+ "version": "1.7.0",
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",