Skip to content

Commit 1d8fe62

Browse files
committed
Add Search
1 parent 54c6cd1 commit 1d8fe62

File tree

7 files changed

+464
-133
lines changed

7 files changed

+464
-133
lines changed

README.md

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -67,8 +67,10 @@ mcp status # Show status of MCP servers in Claude Desktop
6767

6868
- [x] Landing page setup
6969
- [x] CLI foundation
70-
- [ ] Server repository structure
70+
- [x] Search
71+
- [ ] Install
7172
- [ ] Server management functionality
73+
- [ ] Support SSE Server
7274
- [ ] Additional client support
7375
- [ ] MCP profiles - collections of tools that can be added to any clients with a single command
7476

pages/favicon.svg

Lines changed: 8 additions & 0 deletions
Loading

pages/index.html

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77
<link rel="preconnect" href="https://fonts.googleapis.com">
88
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
99
<link href="https://fonts.googleapis.com/css2?family=Fira+Code:wght@400;600&family=Inter:wght@300;400;600;700&display=swap" rel="stylesheet">
10+
<link rel="icon" href="favicon.svg" type="image/svg+xml">
1011
<style>
1112
:root {
1213
--bg-color: #0f1117;

src/mcp/cli.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -107,8 +107,10 @@ def main(ctx, help_flag):
107107
commands_table.add_row(" [cyan]client[/]", "Manage the active MCP client.")
108108
commands_table.add_row(" [cyan]edit[/]", "View or edit the active MCP client's configuration file.")
109109
commands_table.add_row(" [cyan]inspector[/]", "Launch the MCP Inspector UI to examine servers.")
110+
commands_table.add_row(" [cyan]install[/]", "Install an MCP server.")
110111
commands_table.add_row(" [cyan]list[/]", "List all installed MCP servers.")
111112
commands_table.add_row(" [cyan]remove[/]", "Remove an installed MCP server.")
113+
commands_table.add_row(" [cyan]search[/]", "Search available MCP servers.")
112114
commands_table.add_row(" [cyan]server[/]", "Manage MCP server processes.")
113115
commands_table.add_row(" [cyan]toggle[/]", "Toggle an MCP server on or off for a client.")
114116
console.print(commands_table)
@@ -117,8 +119,6 @@ def main(ctx, help_flag):
117119
console.print("")
118120
console.print("[bold yellow]Coming Soon:[/]")
119121
coming_soon_table = Table(show_header=False, box=None, padding=(0, 2, 0, 0))
120-
coming_soon_table.add_row(" [yellow]install[/]", "Install an MCP server.")
121-
coming_soon_table.add_row(" [yellow]search[/]", "Search available MCP servers.")
122122
coming_soon_table.add_row(" [yellow]status[/]", "Show status of MCP servers in Claude Desktop.")
123123
console.print(coming_soon_table)
124124

src/mcp/commands/install.py

Lines changed: 157 additions & 48 deletions
Original file line numberDiff line numberDiff line change
@@ -2,86 +2,195 @@
22
Install command for MCP
33
"""
44

5+
import os
6+
import json
7+
import subprocess
8+
from datetime import datetime
9+
510
import click
611
from rich.console import Console
7-
from rich.progress import Progress
12+
from rich.progress import Progress, SpinnerColumn, TextColumn
13+
from rich.prompt import Confirm
14+
from rich.panel import Panel
815

916
from mcp.utils.repository import RepositoryManager
1017
from mcp.utils.config import ConfigManager
18+
from mcp.utils.client_detector import detect_installed_clients
1119

1220
console = Console()
1321
repo_manager = RepositoryManager()
1422
config_manager = ConfigManager()
1523

1624
@click.command()
1725
@click.argument("server_name")
18-
@click.option("--version", help="Specific version to install")
19-
@click.option("--client", help="Enable for a specific client after installation")
20-
def install(server_name, version, client=None):
26+
@click.option("--force", is_flag=True, help="Force reinstall if server is already installed")
27+
def install(server_name, force=False):
2128
"""Install an MCP server.
2229
2330
Examples:
24-
mcp install filesystem
25-
mcp install filesystem --version=1.0.0
26-
mcp install filesystem --client=cursor
31+
mcp install time
32+
mcp install github
33+
mcp install everything --force
2734
"""
28-
if version:
29-
console.print(f"[bold green]Installing MCP server:[/] {server_name} (version {version})")
30-
else:
31-
console.print(f"[bold green]Installing latest version of MCP server:[/] {server_name}")
32-
3335
# Check if already installed
34-
if config_manager.get_server_info(server_name):
35-
console.print(f"[yellow]Server '{server_name}' is already installed.[/]")
36-
console.print("Use 'mcp update' to update it to a newer version.")
36+
existing_server = config_manager.get_server_info(server_name)
37+
if existing_server and not force:
38+
console.print(f"[yellow]Server '{server_name}' is already installed (v{existing_server.get('version', 'unknown')}).[/]")
39+
console.print("Use 'mcp install --force' to reinstall or 'mcp update' to update it to a newer version.")
3740
return
3841

39-
# Search for the server
42+
# Get server metadata from repository
4043
server_metadata = repo_manager.get_server_metadata(server_name)
4144
if not server_metadata:
42-
console.print(f"[bold red]Error:[/] Server '{server_name}' not found in repository.")
45+
console.print(f"[bold red]Error:[/] Server '{server_name}' not found in registry.")
46+
console.print(f"Available servers: {', '.join(repo_manager._fetch_servers().keys())}")
4347
return
4448

45-
# Check version compatibility
46-
if version and server_metadata["version"] != version:
47-
console.print(f"[bold red]Error:[/] Version {version} not found. Available version: {server_metadata['version']}")
48-
return
49+
# Display server information
50+
display_name = server_metadata.get("display_name", server_name)
51+
description = server_metadata.get("description", "No description available")
52+
available_version = server_metadata.get("version")
53+
author_info = server_metadata.get("author", {})
54+
author_name = author_info.get("name", "Unknown")
55+
license_info = server_metadata.get("license", "Unknown")
4956

50-
if not version:
51-
version = server_metadata["version"]
52-
console.print(f"Using latest version: {version}")
57+
# Use the available version
58+
version = available_version
5359

54-
# Download server (in a real implementation, this would actually download files)
55-
with Progress() as progress:
56-
task = progress.add_task(f"Downloading {server_name}...", total=100)
57-
# Simulate download progress
58-
for i in range(101):
59-
progress.update(task, completed=i)
60-
if i < 100:
61-
import time
62-
time.sleep(0.02)
60+
# Display server information
61+
console.print(Panel(
62+
f"[bold]{display_name}[/] [dim]v{version}[/]\n" +
63+
f"[italic]{description}[/]\n\n" +
64+
f"Author: {author_name}\n" +
65+
f"License: {license_info}",
66+
title="Server Information",
67+
border_style="green",
68+
))
6369

64-
# Register the server in our config
70+
# Check for API key requirements
71+
requirements = server_metadata.get("requirements", {})
72+
needs_api_key = requirements.get("api_key", False)
73+
auth_type = requirements.get("authentication")
74+
75+
if needs_api_key:
76+
console.print("[yellow]Note:[/] This server requires an API key or authentication.")
77+
if auth_type:
78+
console.print(f"Authentication type: [bold]{auth_type}[/]")
79+
80+
# Installation preparation
81+
if not force and existing_server:
82+
if not Confirm.ask(f"Server '{server_name}' is already installed. Do you want to reinstall?"):
83+
return
84+
85+
# Create server directory
86+
server_dir = os.path.expanduser(f"~/.config/mcp/servers/{server_name}")
87+
os.makedirs(server_dir, exist_ok=True)
88+
89+
# Get installation instructions
90+
installation = server_metadata.get("installation", {})
91+
install_command = installation.get("command")
92+
install_args = installation.get("args", [])
93+
package_name = installation.get("package")
94+
env_vars = installation.get("env", {})
95+
96+
if not install_command or not install_args:
97+
console.print(f"[bold red]Error:[/] Invalid installation information for server '{server_name}'.")
98+
return
99+
100+
# Download and install server
101+
with Progress(
102+
SpinnerColumn(),
103+
TextColumn("[bold green]{task.description}[/]"),
104+
console=console
105+
) as progress:
106+
# Download metadata
107+
progress.add_task("Downloading server metadata...", total=None)
108+
# Save metadata to server directory
109+
metadata_path = os.path.join(server_dir, "metadata.json")
110+
with open(metadata_path, "w") as f:
111+
json.dump(server_metadata, f, indent=2)
112+
113+
# Install using the specified command and args
114+
progress.add_task(f"Installing {server_name} v{version}...", total=None)
115+
116+
try:
117+
# Prepare environment variables
118+
env = os.environ.copy()
119+
120+
# Replace variable placeholders with values from environment
121+
for key, value in env_vars.items():
122+
if isinstance(value, str) and value.startswith("${"):
123+
env_var_name = value[2:-1] # Extract variable name from ${NAME}
124+
env_value = os.environ.get(env_var_name, "")
125+
env[key] = env_value
126+
127+
# Warn if variable is not set
128+
if not env_value and needs_api_key:
129+
console.print(f"[yellow]Warning:[/] Environment variable {env_var_name} is not set")
130+
else:
131+
env[key] = value
132+
133+
# Run installation command
134+
if install_command:
135+
full_command = [install_command] + install_args
136+
console.print(f"Running: [dim]{' '.join(full_command)}[/]")
137+
138+
# Capture installation process output
139+
result = subprocess.run(
140+
full_command,
141+
env=env,
142+
stdout=subprocess.PIPE,
143+
stderr=subprocess.PIPE,
144+
text=True,
145+
check=False
146+
)
147+
148+
if result.returncode != 0:
149+
console.print(f"[bold red]Installation failed with error code {result.returncode}[/]")
150+
console.print(f"[red]{result.stderr}[/]")
151+
return
152+
except Exception as e:
153+
console.print(f"[bold red]Error during installation:[/] {str(e)}")
154+
return
155+
156+
# Create server configuration
65157
server_info = {
66158
"name": server_name,
67-
"display_name": server_metadata["display_name"],
159+
"display_name": display_name,
68160
"version": version,
69-
"description": server_metadata["description"],
161+
"description": description,
70162
"status": "stopped",
71-
"install_date": "2025-03-22", # In a real implementation, use current date
72-
"path": f"~/.config/mcp/servers/{server_name}"
163+
"install_date": datetime.now().strftime("%Y-%m-%d"),
164+
"path": server_dir,
165+
"package": package_name
73166
}
167+
168+
# Register the server in our config
74169
config_manager.register_server(server_name, server_info)
75170

76-
console.print(f"[bold green]Successfully installed {server_name} v{version}![/]")
171+
console.print(f"[bold green]Successfully installed {display_name} v{version}![/]")
77172

78-
# If client option specified, enable for that client
79-
if client:
80-
if client not in config_manager.get_config()["clients"]:
81-
console.print(f"[yellow]Warning: Unknown client '{client}'. Server not enabled for any client.[/]")
173+
# Handle client enablement - automatically enable for active client
174+
active_client = config_manager.get_active_client()
175+
installed_clients = detect_installed_clients()
176+
177+
# Enable for active client if installed
178+
if active_client and installed_clients.get(active_client, False):
179+
success = config_manager.enable_server_for_client(server_name, active_client)
180+
if success:
181+
console.print(f"[green]Enabled {server_name} for active client: {active_client}[/]")
82182
else:
83-
success = config_manager.enable_server_for_client(server_name, client)
84-
if success:
85-
console.print(f"[green]Enabled {server_name} for {client}[/]")
86-
else:
87-
console.print(f"[yellow]Failed to enable {server_name} for {client}[/]")
183+
console.print(f"[yellow]Failed to enable {server_name} for {active_client}[/]")
184+
185+
# Display usage examples if available
186+
examples = server_metadata.get("examples", [])
187+
if examples:
188+
console.print("\n[bold]Usage Examples:[/]")
189+
for i, example in enumerate(examples, 1):
190+
title = example.get("title", f"Example {i}")
191+
description = example.get("description", "")
192+
prompt = example.get("prompt", "")
193+
194+
console.print(f" [cyan]{title}[/]: {description}")
195+
if prompt:
196+
console.print(f" Try: [italic]\"{prompt}\"[/]\n")

0 commit comments

Comments
 (0)