mcpick 0.0.2 → 0.0.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.
@@ -0,0 +1,32 @@
1
+ # McPick Development Instructions
2
+
3
+ **Always reference these instructions first and fallback to search or
4
+ bash commands only when you encounter unexpected information that does
5
+ not match the info here.**
6
+
7
+ ## Working Effectively
8
+
9
+ ### Prerequisites and Setup
10
+
11
+ - Install Node.js >=22.0.0
12
+ - Install pnpm globally: `npm install -g pnpm` (takes ~2 seconds)
13
+
14
+ ### Development Commands
15
+
16
+ - **Format code**: `pnpm run format`
17
+ - **Build**: `pnpm run build`
18
+
19
+ ## Validation Requirements
20
+
21
+ ### ALWAYS run these before submitting changes:
22
+
23
+ 1. `pnpm run format` - Auto-format all code
24
+ 2. `pnpm run build` - Check for build issues
25
+
26
+ #### Add changeset once you're done
27
+
28
+ Run `pnpm changeset` then follow the prompts. Use this after having
29
+ finished the task. Most of the time this is a patch release for
30
+ `mcpick`. Use a short and descriptive message. Always prefix the
31
+ message with either `fix`, `feat`, `breaking`, or `chore` (most likely
32
+ `fix` since you're mostly working on bugfixes).
package/CHANGELOG.md CHANGED
@@ -1,5 +1,12 @@
1
1
  # mcpick
2
2
 
3
+ ## 0.0.3
4
+
5
+ ### Patch Changes
6
+
7
+ - 158520e: fix: extract duplicated server details display logic into
8
+ reusable function
9
+
3
10
  ## 0.0.2
4
11
 
5
12
  ### Patch Changes
package/README.md CHANGED
@@ -1,9 +1,27 @@
1
- # MCPick
1
+ # McPick
2
2
 
3
3
  A CLI tool for dynamically managing MCP server configurations in
4
4
  Claude Code. Enable and disable MCP servers on-demand to optimize
5
5
  context usage and performance.
6
6
 
7
+ ## Installation
8
+
9
+ ### One-time Usage
10
+
11
+ ```bash
12
+ pnpm dlx mcpick
13
+ # or
14
+ npx mcpick
15
+ ```
16
+
17
+ ### Global Installation
18
+
19
+ ```bash
20
+ pnpm install -g mcpick
21
+ # or
22
+ npm install -g mcpick
23
+ ```
24
+
7
25
  ## The Problem
8
26
 
9
27
  Using the Claude Code `/doctor` command you may see something like
@@ -31,7 +49,7 @@ This can lead to:
31
49
 
32
50
  ## The Solution
33
51
 
34
- MCPick provides an intuitive CLI menu to:
52
+ McPick provides an intuitive CLI menu to:
35
53
 
36
54
  - ✅ **Toggle servers on/off** - Enable only the MCP servers you need
37
55
  for your current task
@@ -49,7 +67,7 @@ MCPick provides an intuitive CLI menu to:
49
67
  ### Interactive Menu
50
68
 
51
69
  ```bash
52
- MCPick - MCP Server Configuration Manager
70
+ McPick - MCP Server Configuration Manager
53
71
 
54
72
  ◆ What would you like to do?
55
73
  │ ● Edit config (Toggle MCP servers on/off)
@@ -1,6 +1,26 @@
1
1
  import { confirm, note, select, text } from '@clack/prompts';
2
2
  import { add_server_to_registry } from '../core/registry.js';
3
3
  import { validate_mcp_server } from '../core/validation.js';
4
+ function format_server_details(server) {
5
+ const details = [`Name: ${server.name}`];
6
+ if ('command' in server) {
7
+ details.push(`Command: ${server.command} ${(server.args || []).join(' ')}`);
8
+ }
9
+ if ('url' in server) {
10
+ details.push(`URL: ${server.url}`);
11
+ }
12
+ details.push(`Description: ${server.description || 'None'}`);
13
+ if (server.type) {
14
+ details.push(`Transport: ${server.type}`);
15
+ }
16
+ if (server.env) {
17
+ details.push(`Environment: ${Object.keys(server.env).length} variables`);
18
+ }
19
+ if ('headers' in server && server.headers) {
20
+ details.push(`Headers: ${Object.keys(server.headers).length} headers`);
21
+ }
22
+ return details;
23
+ }
4
24
  export async function add_server() {
5
25
  try {
6
26
  // First, ask how they want to configure the server
@@ -75,6 +95,7 @@ export async function add_server() {
75
95
  return;
76
96
  let server_data = {
77
97
  name: name.trim(),
98
+ type: 'stdio',
78
99
  command: command.trim(),
79
100
  args,
80
101
  ...(description &&
@@ -97,11 +118,12 @@ export async function add_server() {
97
118
  });
98
119
  if (typeof transport_type === 'symbol')
99
120
  return;
100
- if (transport_type !== 'stdio') {
101
- server_data.type = transport_type;
102
- }
121
+ server_data.type = transport_type;
103
122
  // URL for non-stdio transports
104
- if (transport_type !== 'stdio') {
123
+ if (transport_type === 'sse' || transport_type === 'http') {
124
+ // Remove stdio-specific fields
125
+ delete server_data.command;
126
+ delete server_data.args;
105
127
  const url = await text({
106
128
  message: 'Server URL:',
107
129
  placeholder: 'e.g., http://localhost:3000',
@@ -158,10 +180,8 @@ export async function add_server() {
158
180
  }
159
181
  }
160
182
  const validated_server = validate_mcp_server(server_data);
161
- note(`Server to add:\n` +
162
- `Name: ${validated_server.name}\n` +
163
- `Command: ${validated_server.command} ${validated_server.args.join(' ')}\n` +
164
- `Description: ${validated_server.description || 'None'}`);
183
+ const details = format_server_details(validated_server);
184
+ note(`Server to add:\n${details.join('\n')}`);
165
185
  const should_add = await confirm({
166
186
  message: 'Add this server to the registry?',
167
187
  });
@@ -213,23 +233,20 @@ async function add_server_from_json() {
213
233
  }
214
234
  const parsed = JSON.parse(jsonString);
215
235
  const server_data = parsed;
236
+ // Normalize the data to match schema expectations
237
+ if (!server_data.type && server_data.command) {
238
+ server_data.type = 'stdio';
239
+ }
240
+ if (server_data.type !== 'stdio') {
241
+ delete server_data.command;
242
+ delete server_data.args;
243
+ }
244
+ if (server_data.command && !server_data.args) {
245
+ server_data.args = [];
246
+ }
216
247
  const validated_server = validate_mcp_server(server_data);
217
- note(`Server to add:\n` +
218
- `Name: ${validated_server.name}\n` +
219
- `Command: ${validated_server.command} ${validated_server.args.join(' ')}\n` +
220
- `Description: ${validated_server.description || 'None'}` +
221
- (validated_server.type
222
- ? `\nTransport: ${validated_server.type}`
223
- : '') +
224
- (validated_server.url
225
- ? `\nURL: ${validated_server.url}`
226
- : '') +
227
- (validated_server.env
228
- ? `\nEnvironment: ${Object.keys(validated_server.env).length} variables`
229
- : '') +
230
- (validated_server.headers
231
- ? `\nHeaders: ${Object.keys(validated_server.headers).length} headers`
232
- : ''));
248
+ const details = format_server_details(validated_server);
249
+ note(`Server to add:\n${details.join('\n')}`);
233
250
  const should_add = await confirm({
234
251
  message: 'Add this server to the registry?',
235
252
  });
@@ -5,7 +5,7 @@ export async function launch_claude_code() {
5
5
  try {
6
6
  s.start('Launching Claude Code...');
7
7
  const claude_process = spawn('claude', ['code'], {
8
- stdio: 'inherit',
8
+ stdio: 'ignore',
9
9
  detached: true,
10
10
  });
11
11
  claude_process.unref();
@@ -1,32 +1,38 @@
1
1
  import * as v from 'valibot';
2
- export const mcp_server_schema = v.object({
3
- name: v.pipe(v.string(), v.minLength(1)),
4
- type: v.optional(v.union([
5
- v.literal('stdio'),
6
- v.literal('sse'),
7
- v.literal('http'),
8
- ])),
2
+ export const mcp_server_schema_stdio = v.object({
3
+ type: v.optional(v.literal('stdio')),
9
4
  command: v.pipe(v.string(), v.minLength(1)),
10
- args: v.array(v.string()),
5
+ args: v.optional(v.array(v.string())),
11
6
  env: v.optional(v.record(v.string(), v.string())),
12
- url: v.optional(v.string()),
7
+ description: v.optional(v.string()),
8
+ });
9
+ export const mcp_server_schema_sse = v.object({
10
+ type: v.literal('sse'),
11
+ env: v.optional(v.record(v.string(), v.string())),
12
+ url: v.pipe(v.string(), v.minLength(1)),
13
+ headers: v.optional(v.record(v.string(), v.string())),
14
+ description: v.optional(v.string()),
15
+ });
16
+ export const mcp_server_schema_http = v.object({
17
+ type: v.literal('http'),
18
+ env: v.optional(v.record(v.string(), v.string())),
19
+ url: v.pipe(v.string(), v.minLength(1)),
13
20
  headers: v.optional(v.record(v.string(), v.string())),
14
21
  description: v.optional(v.string()),
15
22
  });
23
+ export const mcp_server_schema_base = v.union([
24
+ mcp_server_schema_stdio,
25
+ mcp_server_schema_sse,
26
+ mcp_server_schema_http,
27
+ ]);
28
+ export const mcp_server_schema = v.intersect([
29
+ v.object({
30
+ name: v.pipe(v.string(), v.minLength(1)),
31
+ }),
32
+ mcp_server_schema_base,
33
+ ]);
16
34
  export const claude_config_schema = v.object({
17
- mcpServers: v.optional(v.record(v.string(), v.object({
18
- type: v.optional(v.union([
19
- v.literal('stdio'),
20
- v.literal('sse'),
21
- v.literal('http'),
22
- ])),
23
- command: v.pipe(v.string(), v.minLength(1)),
24
- args: v.array(v.string()),
25
- env: v.optional(v.record(v.string(), v.string())),
26
- url: v.optional(v.string()),
27
- headers: v.optional(v.record(v.string(), v.string())),
28
- description: v.optional(v.string()),
29
- }))),
35
+ mcpServers: v.optional(v.record(v.string(), mcp_server_schema_base)),
30
36
  });
31
37
  export const server_registry_schema = v.object({
32
38
  servers: v.array(mcp_server_schema),
package/dist/index.js CHANGED
@@ -40,7 +40,7 @@ async function main() {
40
40
  {
41
41
  value: 'exit',
42
42
  label: 'Exit',
43
- hint: 'Quit MCPick',
43
+ hint: 'Quit MCPick (Esc)',
44
44
  },
45
45
  ],
46
46
  });
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "mcpick",
3
- "version": "0.0.2",
3
+ "version": "0.0.3",
4
4
  "description": "Dynamic MCP server configuration manager for Claude Code",
5
5
  "type": "module",
6
6
  "main": "./dist/index.js",
@@ -25,9 +25,9 @@
25
25
  },
26
26
  "devDependencies": {
27
27
  "@changesets/cli": "^2.29.7",
28
- "@types/node": "^24.5.2",
28
+ "@types/node": "^24.6.1",
29
29
  "prettier": "^3.6.2",
30
- "typescript": "^5.9.2"
30
+ "typescript": "^5.9.3"
31
31
  },
32
32
  "scripts": {
33
33
  "build": "tsc",