Skip to content

Commit 2ee9442

Browse files
authored
Big architecture refactor across the project (#1)
v0.3.0 – Major Refactor Release 🚀 Highlights • Big architecture refactor across the project • Code is now more organized and modular • Version bumped to 0.3.0 🔧 Changes • Project Restructure: Set up a new folder structure with clear module separation. • Tool Management: Moved tool logic into a dedicated ToolManager class. • Model Management: Created ModelManager to handle all model-related tasks. • Server Connection: Introduced ServerConnector and improved server discovery. • Configuration: Centralized config logic into ConfigManager and added validation. • Code Cleanup: Removed unused code, simplified components, and polished the structure. • Readme & CLI: Updated the main README and improved CLI help messages.
1 parent b9012ab commit 2ee9442

19 files changed

+1539
-802
lines changed

README.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -56,7 +56,7 @@ git clone https://github.com/jonigl/mcp-client-for-ollama.git
5656
cd mcp-client-for-ollama
5757
uv venv && source .venv/bin/activate
5858
uv pip install .
59-
uv run mcp_client_for_ollama/client.py
59+
uv run -m mcp_client_for_ollama.client
6060
```
6161

6262
## Usage

cli-package/pyproject.toml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
[project]
22
name = "ollmcp"
3-
version = "0.2.5"
3+
version = "0.3.0"
44
description = "CLI for MCP Client for Ollama - An easy-to-use command for interacting with Ollama through MCP"
55
readme = "README.md"
66
requires-python = ">=3.10"
@@ -9,7 +9,7 @@ authors = [
99
{name = "Jonathan Löwenstern"}
1010
]
1111
dependencies = [
12-
"mcp-client-for-ollama==0.2.5"
12+
"mcp-client-for-ollama==0.3.0"
1313
]
1414

1515
[project.scripts]

mcp_client_for_ollama/__init__.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,3 @@
11
"""MCP Client for Ollama package."""
22

3-
__version__ = "0.2.5"
3+
__version__ = "0.3.0"

mcp_client_for_ollama/client.py

Lines changed: 126 additions & 796 deletions
Large diffs are not rendered by default.

mcp_client_for_ollama/config/__init__.py

Whitespace-only changes.
Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
"""Default configuration settings for MCP Client for Ollama.
2+
3+
This module provides default settings and paths used throughout the application.
4+
"""
5+
6+
import os
7+
from ..utils.constants import DEFAULT_MODEL, DEFAULT_CONFIG_FILE, DEFAULT_CONFIG_DIR
8+
9+
def default_config() -> dict:
10+
"""Get default configuration settings.
11+
12+
Returns:
13+
dict: Default configuration dictionary
14+
"""
15+
16+
return {
17+
"model": DEFAULT_MODEL,
18+
"enabledTools": {}, # Will be populated with available tools
19+
"contextSettings": {
20+
"retainContext": True
21+
}
22+
}
23+
24+
def get_config_path(config_name: str = "default") -> str:
25+
"""Get the path to a specific configuration file.
26+
27+
Args:
28+
config_name: Name of the configuration (default: "default")
29+
30+
Returns:
31+
str: Path to the configuration file
32+
"""
33+
# Ensure the directory exists
34+
os.makedirs(DEFAULT_CONFIG_DIR, exist_ok=True)
35+
36+
# Sanitize the config name
37+
config_name = ''.join(c for c in config_name if c.isalnum() or c in ['-', '_']).lower() or "default"
38+
39+
if config_name == "default":
40+
return os.path.join(DEFAULT_CONFIG_DIR, DEFAULT_CONFIG_FILE)
41+
else:
42+
return os.path.join(DEFAULT_CONFIG_DIR, f"{config_name}.json")
Lines changed: 190 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,190 @@
1+
"""Configuration management for MCP Client for Ollama.
2+
3+
This module handles loading, saving, and validating configuration settings for
4+
the MCP Client for Ollama, including tool settings and model preferences.
5+
"""
6+
7+
import json
8+
import os
9+
from typing import Dict, Any, Optional
10+
from rich.console import Console
11+
from rich.panel import Panel
12+
from ..utils.constants import DEFAULT_CONFIG_DIR, DEFAULT_CONFIG_FILE
13+
from .defaults import default_config
14+
15+
class ConfigManager:
16+
"""Manages configuration for the MCP Client for Ollama.
17+
18+
This class handles loading, saving, and validating configuration settings,
19+
including enabled tools, selected model, and context retention preferences.
20+
"""
21+
22+
def __init__(self, console: Optional[Console] = None):
23+
"""Initialize the ConfigManager.
24+
25+
Args:
26+
console: Rich console for output (optional)
27+
"""
28+
self.console = console or Console()
29+
30+
def load_configuration(self, config_name: Optional[str] = None) -> Dict[str, Any]:
31+
"""Load tool configuration and model settings from a file.
32+
33+
Args:
34+
config_name: Optional name of the config to load (defaults to 'default')
35+
36+
Returns:
37+
Dict containing the configuration settings
38+
"""
39+
# Default to 'default' if no config name provided
40+
if not config_name:
41+
config_name = "default"
42+
43+
# Sanitize filename
44+
config_name = self._sanitize_config_name(config_name)
45+
46+
# Create config file path
47+
config_path = self._get_config_path(config_name)
48+
49+
# Check if config file exists
50+
if not os.path.exists(config_path):
51+
self.console.print(Panel(
52+
f"[yellow]Configuration file not found:[/yellow]\n"
53+
f"[blue]{config_path}[/blue]",
54+
title="Config Not Found", border_style="yellow", expand=False
55+
))
56+
return default_config()
57+
58+
# Read config file
59+
try:
60+
with open(config_path, 'r') as f:
61+
config_data = json.load(f)
62+
63+
# Validate loaded configuration and provide defaults for missing fields
64+
validated_config = self._validate_config(config_data)
65+
66+
self.console.print(Panel(
67+
f"[green]Configuration loaded successfully from:[/green]\n"
68+
f"[blue]{config_path}[/blue]",
69+
title="Config Loaded", border_style="green", expand=False
70+
))
71+
return validated_config
72+
73+
except Exception as e:
74+
self.console.print(Panel(
75+
f"[red]Error loading configuration:[/red]\n"
76+
f"{str(e)}",
77+
title="Error", border_style="red", expand=False
78+
))
79+
return default_config()
80+
81+
def save_configuration(self, config_data: Dict[str, Any], config_name: Optional[str] = None) -> bool:
82+
"""Save tool configuration and model settings to a file.
83+
84+
Args:
85+
config_data: Dictionary containing the configuration to save
86+
config_name: Optional name for the config (defaults to 'default')
87+
88+
Returns:
89+
bool: True if saved successfully, False otherwise
90+
"""
91+
# Create config directory if it doesn't exist
92+
os.makedirs(DEFAULT_CONFIG_DIR, exist_ok=True)
93+
94+
# Default to 'default' if no config name provided
95+
if not config_name:
96+
config_name = "default"
97+
98+
# Sanitize filename
99+
config_name = self._sanitize_config_name(config_name)
100+
101+
# Create config file path
102+
config_path = self._get_config_path(config_name)
103+
104+
# Write to file
105+
try:
106+
with open(config_path, 'w') as f:
107+
json.dump(config_data, f, indent=2)
108+
109+
self.console.print(Panel(
110+
f"[green]Configuration saved successfully to:[/green]\n"
111+
f"[blue]{config_path}[/blue]",
112+
title="Config Saved", border_style="green", expand=False
113+
))
114+
return True
115+
116+
except Exception as e:
117+
self.console.print(Panel(
118+
f"[red]Error saving configuration:[/red]\n"
119+
f"{str(e)}",
120+
title="Error", border_style="red", expand=False
121+
))
122+
return False
123+
124+
def reset_configuration(self) -> Dict[str, Any]:
125+
"""Reset tool configuration to default (all tools enabled).
126+
127+
Returns:
128+
Dict containing the default configuration
129+
"""
130+
config = default_config()
131+
132+
self.console.print(Panel(
133+
"[green]Configuration reset to defaults![/green]\n"
134+
"• All tools enabled\n"
135+
"• Context retention enabled",
136+
title="Config Reset", border_style="green", expand=False
137+
))
138+
139+
return config
140+
141+
def _sanitize_config_name(self, config_name: str) -> str:
142+
"""Sanitize configuration name for use in filenames.
143+
144+
Args:
145+
config_name: Name to sanitize
146+
147+
Returns:
148+
str: Sanitized name safe for use in filenames
149+
"""
150+
sanitized = ''.join(c for c in config_name if c.isalnum() or c in ['-', '_']).lower()
151+
return sanitized or "default"
152+
153+
def _get_config_path(self, config_name: str) -> str:
154+
"""Get the full path to a configuration file.
155+
156+
Args:
157+
config_name: Name of the configuration
158+
159+
Returns:
160+
str: Full path to the configuration file
161+
"""
162+
if config_name == "default":
163+
return os.path.join(DEFAULT_CONFIG_DIR, DEFAULT_CONFIG_FILE)
164+
else:
165+
return os.path.join(DEFAULT_CONFIG_DIR, f"{config_name}.json")
166+
167+
def _validate_config(self, config_data: Dict[str, Any]) -> Dict[str, Any]:
168+
"""Validate configuration data and provide defaults for missing fields.
169+
170+
Args:
171+
config_data: Configuration data to validate
172+
173+
Returns:
174+
Dict: Validated configuration with defaults applied where needed
175+
"""
176+
# Start with default configuration
177+
validated = default_config()
178+
179+
# Apply values from the loaded configuration if they exist
180+
if "model" in config_data:
181+
validated["model"] = config_data["model"]
182+
183+
if "enabledTools" in config_data and isinstance(config_data["enabledTools"], dict):
184+
validated["enabledTools"] = config_data["enabledTools"]
185+
186+
if "contextSettings" in config_data and isinstance(config_data["contextSettings"], dict):
187+
if "retainContext" in config_data["contextSettings"]:
188+
validated["contextSettings"]["retainContext"] = bool(config_data["contextSettings"]["retainContext"])
189+
190+
return validated

mcp_client_for_ollama/models/__init__.py

Whitespace-only changes.

0 commit comments

Comments
 (0)