Skip to content

Commit 4799698

Browse files
feat: improve profile management
1 parent 2c2bed0 commit 4799698

24 files changed

+333
-466
lines changed

README.md

Lines changed: 5 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -40,7 +40,7 @@ Or choose [other installation methods](#-other-installation-methods) like `brew`
4040
MCPM simplifies the installation, configuration, and management of Model Context Protocol servers and their configurations across different applications (clients). Key features include:
4141

4242
- ✨ Easy addition and removal of MCP server configurations for supported clients.
43-
- 📋 Centralized management using profiles: group server configurations together and activate/deactivate them easily.
43+
- 📋 Centralized management using profiles: group server configurations together and add/remove them to client easily.
4444
- 🔍 Discovery of available MCP servers through a central registry.
4545
- 🔌 MCPM Router for aggregating multiple MCP servers behind a single endpoint with shared sessions.
4646
- 💻 A command-line interface (CLI) for all management tasks.
@@ -78,7 +78,6 @@ mcpm --version # Display the current version of MCPM
7878

7979
```bash
8080
mcpm client ls # List all supported MCP clients, detect installed ones, and show active client
81-
mcpm client set CLIENT # Set the active client for subsequent commands
8281
mcpm client edit # Open the active client's MCP configuration file in an external editor
8382
```
8483

@@ -114,25 +113,22 @@ mcpm pop [SERVER_NAME] # Restore the last stashed server, or a specific one b
114113

115114
Profiles are named collections of server configurations. They allow you to easily switch between different sets of MCP servers. For example, you might have a `work` profile and a `personal` profile, each containing different servers. Or you might have a `production` profile and a `development` profile, each containing different configurations for the same servers.
116115

117-
The currently *active* profile's servers are typically used by features like the MCPM Router. Use `mcpm activate` to set the active profile.
116+
The currently *active* profile's servers are typically used by features like the MCPM Router. Use `mcpm target set %profile_name` to set the active profile.
118117

119118
```bash
120119
# 🔄 Profile Lifecycle
121120
mcpm profile ls # List all available MCPM profiles
122121
mcpm profile add PROFILE_NAME # Add a new, empty profile
123122
mcpm profile rm PROFILE_NAME # Remove a profile (does not delete servers within it)
124123
mcpm profile rename OLD_NAME NEW_NAME # Rename a profile
125-
126-
# ✅ Activating Profiles
127-
mcpm activate PROFILE_NAME # Activate a profile, applying its servers to the active client
128-
mcpm deactivate # Deactivate the current profile for the active client
124+
mcpm add %profile_name # Add a profile to the active client
129125
```
130126

131127
### 🔌 Router Management (`router`)
132128

133129
The MCPM Router runs as a background daemon process, acting as a stable endpoint (e.g., `http://localhost:6276`) that intelligently routes incoming MCP requests to the appropriate server based on the currently **active profile**.
134130

135-
This allows you to change the underlying servers (by switching profiles with `mcpm activate`) without reconfiguring your client applications. They can always point to the MCPM Router's address.
131+
This allows you to change the underlying servers (by switching profiles with `mcpm target set %profile_name`) without reconfiguring your client applications. They can always point to the MCPM Router's address.
136132

137133
The Router also maintains persistent connections to MCP servers, enabling multiple clients to share these server sessions. This eliminates the need to start separate server instances for each client, significantly reducing resource usage and startup time. Learn more about these advanced capabilities in [Advanced Features](docs/advanced_features.md).
138134

@@ -168,7 +164,7 @@ The MCP Registry is a central repository of available MCP servers that can be in
168164
- [x] Basic server management (`mcpm add`, `mcpm ls`, `mcpm rm`)
169165
- [x] Registry integration (`mcpm search`, adding by name)
170166
- [x] Router functionality (`mcpm router`)
171-
- [x] MCP Profiles (`mcpm profile`, `mcpm activate/deactivate`)
167+
- [x] MCP Profiles (`mcpm profile`)
172168
- [x] Server copying/moving (`mcpm cp`, `mcpm mv`)
173169
- [x] Server stashing (`mcpm stash`, `mcpm pop`)
174170
- [x] Router remote share (`mcpm router share`) remotely access local router and mcp servers

README.zh-CN.md

Lines changed: 3 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -112,7 +112,6 @@ mcpm --version # 显示 MCPM 的当前版本
112112

113113
```bash
114114
mcpm client ls # 列出所有支持的 MCP 客户端,检测已安装的客户端,并显示活动客户端
115-
mcpm client set CLIENT # 为后续命令设置活动客户端
116115
mcpm client edit # 在外部编辑器中打开活动客户端的 MCP 配置文件
117116
```
118117

@@ -148,25 +147,21 @@ mcpm pop [SERVER_NAME] # 恢复最后暂存的服务器,或按名称恢复
148147

149148
配置文件是服务器配置的命名集合。它们允许您轻松切换不同的 MCP 服务器集。例如,您可能有一个 `work` 配置文件和一个 `personal` 配置文件,每个都包含不同的服务器。或者,您可能有一个 `production` 配置文件和一个 `development` 配置文件,每个都包含同一服务器的不同配置。
150149

151-
当前*活动*配置文件的服务器通常由 MCPM 路由器等功能使用。使用 `mcpm activate` 设置活动配置文件。
150+
当前*活动*配置文件的服务器通常由 MCPM 路由器等功能使用。使用 `mcpm target set %profile_name` 设置活动配置文件。
152151

153152
```bash
154153
# 🔄 配置文件生命周期
155154
mcpm profile ls # 列出所有可用的 MCPM 配置文件
156155
mcpm profile add PROFILE_NAME # 添加新的空配置文件
157156
mcpm profile rm PROFILE_NAME # 删除配置文件(不删除其中的服务器)
158157
mcpm profile rename OLD_NAME NEW_NAME # 重命名配置文件
159-
160-
# ✅ 激活配置文件
161-
mcpm activate PROFILE_NAME # 激活配置文件,将其服务器应用于活动客户端
162-
mcpm deactivate # 为活动客户端停用当前配置文件
163158
```
164159

165160
### 🔌 路由器管理 (`router`)
166161

167162
MCPM 路由器作为后台守护进程运行,充当稳定端点(例如 `http://localhost:6276`),根据当前**活动配置文件**智能地将传入的 MCP 请求路由到适当的服务器。
168163

169-
这允许您通过切换配置文件(使用 `mcpm activate`)来更改底层服务器,而无需重新配置客户端应用程序。它们可以始终指向 MCPM 路由器的地址。
164+
这允许您通过切换配置文件(使用 `mcpm target set %profile_name`)来更改底层服务器,而无需重新配置客户端应用程序。它们可以始终指向 MCPM 路由器的地址。
170165

171166
路由器还维护与 MCP 服务器的持久连接,使多个客户端能够共享这些服务器会话。这消除了为每个客户端启动单独服务器实例的需要,显著减少资源使用和启动时间。在 [高级功能](docs/advanced_features.md) 中了解有关这些高级功能的更多信息。
172167

@@ -202,7 +197,7 @@ MCP 注册表是可使用 MCPM 安装的可用 MCP 服务器的中央存储库
202197
- [x] 基本服务器管理 (`mcpm add`, `mcpm ls`, `mcpm rm`)
203198
- [x] 注册表集成 (`mcpm search`, 按名称添加)
204199
- [x] 路由器功能 (`mcpm router`)
205-
- [x] MCP 配置文件 (`mcpm profile`, `mcpm activate/deactivate`)
200+
- [x] MCP 配置文件 (`mcpm profile`)
206201
- [x] 服务器复制/移动 (`mcpm cp`, `mcpm mv`)
207202
- [x] 服务器暂存 (`mcpm stash`, `mcpm pop`)
208203
- [x] 路由器远程分享 (`mcpm router share`) 远程访问本地路由器和 MCP 服务器

pages/index.html

Lines changed: 5 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -871,14 +871,6 @@ <h3><span><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox
871871
</div>
872872
</div>
873873

874-
<div class="feature">
875-
<h3><span><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><polyline points="1 4 1 10 7 10"></polyline><polyline points="23 20 23 14 17 14"></polyline><path d="M20.49 9A9 9 0 0 0 5.64 5.64L1 10m22 4l-4.64 4.36A9 9 0 0 1 3.51 15"></path></svg></span> Activate Profiles</h3>
876-
<p>Switch between different sets of server configurations:</p>
877-
<div class="code-block">
878-
<code><span class="command-prompt">$</span> mcpm activate work</code>
879-
<button class="copy-button" data-command="mcpm activate work"><svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><rect x="9" y="9" width="13" height="13" rx="2" ry="2"></rect><path d="M5 15H4a2 2 0 0 1-2-2V4a2 2 0 0 1 2-2h9a2 2 0 0 1 2 2v1"></path></svg></button>
880-
</div>
881-
</div>
882874

883875
<div class="feature">
884876
<h3><span><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><line x1="8" y1="6" x2="21" y2="6"></line><line x1="8" y1="12" x2="21" y2="12"></line><line x1="8" y1="18" x2="21" y2="18"></line><line x1="3" y1="6" x2="3.01" y2="6"></line><line x1="3" y1="12" x2="3.01" y2="12"></line><line x1="3" y1="18" x2="3.01" y2="18"></line></svg></span> List Profiles</h3>
@@ -1013,10 +1005,10 @@ <h2>Client Management</h2>
10131005
<div class="features">
10141006
<div class="feature">
10151007
<h3><span><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M17 21v-2a4 4 0 0 0-4-4H5a4 4 0 0 0-4 4v2"></path><circle cx="9" cy="7" r="4"></circle><path d="M23 21v-2a4 4 0 0 0-3-3.87"></path><path d="M16 3.13a4 4 0 0 1 0 7.75"></path></svg></span> Set Active Client</h3>
1016-
<p>Easily switch between and manage MCP clients:</p>
1008+
<p>Easily switch between and manage MCP clients/profiles:</p>
10171009
<div class="code-block">
1018-
<code><span class="command-prompt">$</span> mcpm client set claude-desktop</code>
1019-
<button class="copy-button" data-command="mcpm client set claude-desktop"><svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><rect x="9" y="9" width="13" height="13" rx="2" ry="2"></rect><path d="M5 15H4a2 2 0 0 1-2-2V4a2 2 0 0 1 2-2h9a2 2 0 0 1 2 2v1"></path></svg></button>
1010+
<code><span class="command-prompt">$</span> mcpm target set @claude-desktop</code>
1011+
<button class="copy-button" data-command="mcpm target set @claude-desktop"><svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><rect x="9" y="9" width="13" height="13" rx="2" ry="2"></rect><path d="M5 15H4a2 2 0 0 1-2-2V4a2 2 0 0 1 2-2h9a2 2 0 0 1 2 2v1"></path></svg></button>
10201012
</div>
10211013
</div>
10221014

@@ -1100,10 +1092,10 @@ <h2>Supported Clients</h2>
11001092
" add my-server",
11011093
" ls",
11021094
" profile add work",
1103-
" activate work",
1095+
" target set %work",
11041096
" router on",
11051097
" stash my-server",
1106-
" client set claude"
1098+
" target set @claude-desktop"
11071099
];
11081100
let currentCommand = 0;
11091101
let charIndex = 0;

src/mcpm/cli.py

Lines changed: 29 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@
2222
router,
2323
search,
2424
stash,
25+
target,
2526
transfer,
2627
)
2728

@@ -94,39 +95,45 @@ def main(ctx, help_flag, version):
9495
return
9596

9697
# Check if a command is being executed (and it's not help, no command, or the client command)
97-
if ctx.invoked_subcommand and ctx.invoked_subcommand != "client" and not help_flag:
98+
if (
99+
ctx.invoked_subcommand
100+
and ctx.invoked_subcommand not in ["target", "client", "profile", "router"]
101+
and not help_flag
102+
):
98103
# Check if active client is set
99-
active_client = client_config_manager.get_active_client()
100-
if not active_client:
101-
console.print("[bold red]Error:[/] No active client set.")
102-
console.print("Please run 'mcpm client set <client-name>' to set an active client.")
103-
console.print("Available clients:")
104+
active_target = client_config_manager.get_active_target()
105+
if not active_target:
106+
console.print("[bold red]Error:[/] No active target set.")
107+
console.print("Please run 'mcpm target set <target>' to set an active target\n")
104108

105109
# Show available clients
106110
from mcpm.clients.client_registry import ClientRegistry
107111

112+
console.print("[bold green]Available Clients, set one with 'mcpm target set @<client>':[/]")
108113
for client in ClientRegistry.get_supported_clients():
109114
console.print(f" - {client}")
110115

116+
from mcpm.profile.profile_config import ProfileConfigManager
117+
118+
# Show available profiles
119+
console.print("[bold green]Available Profiles, set one with 'mcpm target set %<profile>':[/]")
120+
profile_manager = ProfileConfigManager()
121+
for profile in profile_manager.list_profiles():
122+
console.print(f" - {profile}")
123+
111124
# Exit with error
112125
ctx.exit(1)
113126
# If no command was invoked or help is requested, show our custom help
114127
if ctx.invoked_subcommand is None or help_flag:
115128
# Get active client
116-
active_client = client_config_manager.get_active_client()
129+
active_target = client_config_manager.get_active_target()
117130

118131
print_logo()
119-
# Get information about installed clients
120-
from mcpm.clients.client_registry import ClientRegistry
121-
122-
installed_clients = ClientRegistry.detect_installed_clients()
123-
124132
# Display active client information and main help
125-
if active_client:
126-
client_status = "[green]✓[/]" if installed_clients.get(active_client, False) else "[yellow]⚠[/]"
127-
console.print(f"[bold magenta]Active client:[/] [yellow]{active_client}[/] {client_status}")
133+
if active_target:
134+
console.print(f"[bold magenta]Active target:[/] [yellow]{active_target}[/]")
128135
else:
129-
console.print("[bold red]No active client set![/] Please run 'mcpm client set <client-name>' to set one.")
136+
console.print("[bold red]No active target set![/] Please run 'mcpm target set <target>' to set one.")
130137
console.print("")
131138

132139
# Display usage info
@@ -144,8 +151,12 @@ def main(ctx, help_flag, version):
144151
# Display available commands in a table
145152
console.print("[bold]Commands:[/]")
146153
commands_table = Table(show_header=False, box=None, padding=(0, 2, 0, 0))
154+
155+
commands_table.add_row("[yellow]work target[/]")
156+
commands_table.add_row(" [cyan]target[/]", "Manage the active MCPM target.")
157+
147158
commands_table.add_row("[yellow]client[/]")
148-
commands_table.add_row(" [cyan]client[/]", "Manage the active MCPM client.")
159+
commands_table.add_row(" [cyan]client[/]", "Manage supported MCPM clients.")
149160

150161
commands_table.add_row("[yellow]server[/]")
151162
commands_table.add_row(" [cyan]search[/]", "Search available MCP servers.")
@@ -161,8 +172,6 @@ def main(ctx, help_flag, version):
161172

162173
commands_table.add_row("[yellow]profile[/]")
163174
commands_table.add_row(" [cyan]profile[/]", "Manage MCPM profiles.")
164-
commands_table.add_row(" [cyan]activate[/]", "Activate a profile.")
165-
commands_table.add_row(" [cyan]deactivate[/]", "Deactivate a profile.")
166175

167176
commands_table.add_row("[yellow]router[/]")
168177
commands_table.add_row(" [cyan]router[/]", "Manage MCP router service.")
@@ -187,14 +196,13 @@ def main(ctx, help_flag, version):
187196
main.add_command(stash.stash)
188197
main.add_command(pop.pop)
189198

199+
main.add_command(target.target)
190200
main.add_command(client.client)
191201
main.add_command(config.config)
192202
main.add_command(inspector.inspector, name="inspector")
193203
main.add_command(profile.profile, name="profile")
194204
main.add_command(transfer.move, name="mv")
195205
main.add_command(transfer.copy, name="cp")
196-
main.add_command(profile.activate)
197-
main.add_command(profile.deactivate)
198206
main.add_command(router.router, name="router")
199207
main.add_command(custom.import_server, name="import")
200208

src/mcpm/clients/client_config.py

Lines changed: 24 additions & 55 deletions
Original file line numberDiff line numberDiff line change
@@ -5,8 +5,8 @@
55
import logging
66
from typing import Any, Dict, List, Optional
77

8-
from mcpm.profile.profile_config import ProfileConfigManager
98
from mcpm.utils.config import ConfigManager
9+
from mcpm.utils.scope import ScopeType, extract_from_scope
1010

1111
logger = logging.getLogger(__name__)
1212

@@ -24,72 +24,41 @@ def _refresh_config(self):
2424
self._config = self.config_manager.get_config()
2525

2626
def get_active_client(self) -> str | None:
27-
"""Get the name of the currently active client or None if not set"""
28-
self._refresh_config()
29-
return self._config.get("active_client")
27+
target = self.get_active_target()
28+
if not target:
29+
return
30+
scope_type, scope = extract_from_scope(target)
31+
if scope_type != ScopeType.CLIENT:
32+
return
33+
return scope
3034

31-
def set_active_client(self, client_name: Optional[str]) -> bool:
32-
"""Set the active client
35+
def set_active_target(self, target_name: str | None) -> bool:
36+
"""Set the active target
3337
3438
Args:
35-
client_name: Name of client to set as active, or None to clear
39+
target_name: Name of target to set as active
3640
3741
Returns:
3842
bool: Success or failure
3943
"""
40-
# If None, remove the active client
41-
if client_name is None:
42-
result = self.config_manager.set_config("active_client", None)
43-
self._refresh_config()
44-
return result
45-
46-
# Get supported clients
47-
from mcpm.clients.client_registry import ClientRegistry
48-
49-
supported_clients = ClientRegistry.get_supported_clients()
50-
51-
if client_name not in supported_clients:
52-
logger.error(f"Unknown client: {client_name}")
53-
return False
54-
55-
# Set the active client
56-
result = self.config_manager.set_config("active_client", client_name)
57-
# refresh the active profile
58-
client = ClientRegistry.get_client_manager(client_name)
59-
self.set_active_profile(client.get_associated_profile()) # type: ignore
44+
# Set the active target
45+
result = self.config_manager.set_config("active_target", target_name)
6046
self._refresh_config()
6147
return result
6248

63-
def get_active_profile(self) -> str | None:
64-
"""Get the name of the currently active profile or None if not set"""
49+
def get_active_target(self) -> str | None:
50+
"""Get the name of the currently active target or None if not set"""
6551
self._refresh_config()
66-
return self._config.get("active_profile")
67-
68-
def set_active_profile(self, profile_name: Optional[str]) -> bool:
69-
"""Set the active profile
70-
71-
Args:
72-
profile_name: Name of profile to set as active, or None to clear
52+
return self._config.get("active_target")
7353

74-
Returns:
75-
bool: Success or failure
76-
"""
77-
# If None, remove the active profile
78-
if profile_name is None:
79-
result = self.config_manager.set_config("active_profile", None)
80-
self._refresh_config()
81-
return result
82-
83-
supported_profiles = ProfileConfigManager().list_profiles()
84-
85-
if profile_name not in supported_profiles:
86-
logger.error(f"Unknown profile: {profile_name}")
87-
return False
88-
89-
# Set the active profile
90-
result = self.config_manager.set_config("active_profile", profile_name)
91-
self._refresh_config()
92-
return result
54+
def get_active_profile(self) -> str | None:
55+
target = self.get_active_target()
56+
if not target:
57+
return
58+
scope_type, scope = extract_from_scope(target)
59+
if scope_type != ScopeType.PROFILE:
60+
return
61+
return scope
9362

9463
def get_supported_clients(self) -> List[str]:
9564
"""Get a list of supported client names"""

0 commit comments

Comments
 (0)