Skip to content
Merged
Show file tree
Hide file tree
Changes from 17 commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 4 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -155,4 +155,7 @@ Thumbs.db
.env.test
.env.production

.actrc
# Database files
*.db
*.sqlite
*.sqlite3
36 changes: 18 additions & 18 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
## [1.0.0](https://github.com/hepivax/mcp-as-a-judge/compare/v0.1.8...v1.0.0) (2025-08-30)
## [1.0.0](https://github.com/OtherVibes/mcp-as-a-judge/compare/v0.1.8...v1.0.0) (2025-08-30)

### ⚠ BREAKING CHANGES

Expand Down Expand Up @@ -56,45 +56,45 @@ Benefits:

### πŸš€ Features

* add CODEOWNERS file to require approval from [@hepivax](https://github.com/hepivax) ([1bd5b29](https://github.com/hepivax/mcp-as-a-judge/commit/1bd5b2961b99519fe9b819363fb56902b21dbb1e))
* configure semantic release with GitHub App token for branch protection bypass ([315cb37](https://github.com/hepivax/mcp-as-a-judge/commit/315cb379fb1b50c0e241c5573322a3ead6e0b41a))
* enforce mandatory online research with List[str] URLs and collaborative workflow ([#11](https://github.com/hepivax/mcp-as-a-judge/issues/11)) ([3b76dc0](https://github.com/hepivax/mcp-as-a-judge/commit/3b76dc0bda287acfbc51ab5aef1586e85eb34b1a))
* separate user and system messages with type-safe Pydantic models ([3f0a688](https://github.com/hepivax/mcp-as-a-judge/commit/3f0a688b9c7839efa8302dd54ab13be497f489e2))
* add CODEOWNERS file to require approval from [@OtherVibes](https://github.com/OtherVibes) ([1bd5b29](https://github.com/OtherVibes/mcp-as-a-judge/commit/1bd5b2961b99519fe9b819363fb56902b21dbb1e))
* configure semantic release with GitHub App token for branch protection bypass ([315cb37](https://github.com/OtherVibes/mcp-as-a-judge/commit/315cb379fb1b50c0e241c5573322a3ead6e0b41a))
* enforce mandatory online research with List[str] URLs and collaborative workflow ([#11](https://github.com/OtherVibes/mcp-as-a-judge/issues/11)) ([3b76dc0](https://github.com/OtherVibes/mcp-as-a-judge/commit/3b76dc0bda287acfbc51ab5aef1586e85eb34b1a))
* separate user and system messages with type-safe Pydantic models ([3f0a688](https://github.com/OtherVibes/mcp-as-a-judge/commit/3f0a688b9c7839efa8302dd54ab13be497f489e2))

### πŸ› Bug Fixes

* correct version to 0.1.9 ([4072bdb](https://github.com/hepivax/mcp-as-a-judge/commit/4072bdbfeda715c7affa19613cbed48ff560d402))
* move prompts into package for reliable installation ([3d2fde6](https://github.com/hepivax/mcp-as-a-judge/commit/3d2fde6143edb3c0598788e5b370fa30dc6163af))
* resolve prompts directory not found in installed package ([d8f7964](https://github.com/hepivax/mcp-as-a-judge/commit/d8f7964f85582fdfe118e70860cee7f988f3d563))
* correct version to 0.1.9 ([4072bdb](https://github.com/OtherVibes/mcp-as-a-judge/commit/4072bdbfeda715c7affa19613cbed48ff560d402))
* move prompts into package for reliable installation ([3d2fde6](https://github.com/OtherVibes/mcp-as-a-judge/commit/3d2fde6143edb3c0598788e5b370fa30dc6163af))
* resolve prompts directory not found in installed package ([d8f7964](https://github.com/OtherVibes/mcp-as-a-judge/commit/d8f7964f85582fdfe118e70860cee7f988f3d563))

### ♻️ Code Refactoring

* use importlib.resources for prompt loading (standard Python approach) ([f106137](https://github.com/hepivax/mcp-as-a-judge/commit/f106137bb69324c6cae9284193a48f734cb8851c))
* use importlib.resources for prompt loading (standard Python approach) ([f106137](https://github.com/OtherVibes/mcp-as-a-judge/commit/f106137bb69324c6cae9284193a48f734cb8851c))

## [0.1.8](https://github.com/hepivax/mcp-as-a-judge/compare/v0.1.7...v0.1.8) (2025-08-30)
## [0.1.8](https://github.com/OtherVibes/mcp-as-a-judge/compare/v0.1.7...v0.1.8) (2025-08-30)

### πŸ› Bug Fixes

* use shell environment variable syntax for PYPI_TOKEN ([1452d4e](https://github.com/hepivax/mcp-as-a-judge/commit/1452d4e712b62f6c6af412cfa77116bca46a6bb7))
* use shell environment variable syntax for PYPI_TOKEN ([1452d4e](https://github.com/OtherVibes/mcp-as-a-judge/commit/1452d4e712b62f6c6af412cfa77116bca46a6bb7))

## [0.1.7](https://github.com/hepivax/mcp-as-a-judge/compare/v0.1.6...v0.1.7) (2025-08-30)
## [0.1.7](https://github.com/OtherVibes/mcp-as-a-judge/compare/v0.1.6...v0.1.7) (2025-08-30)

### πŸ› Bug Fixes

* correct PYPI token environment variable name ([3112ee4](https://github.com/hepivax/mcp-as-a-judge/commit/3112ee4ebbca75510a9e2069fe49a84272dbb382))
* use correct PYPI_TOKEN environment variable ([d45a096](https://github.com/hepivax/mcp-as-a-judge/commit/d45a096773c28a9edc1e5e393d95c14687de467a))
* correct PYPI token environment variable name ([3112ee4](https://github.com/OtherVibes/mcp-as-a-judge/commit/3112ee4ebbca75510a9e2069fe49a84272dbb382))
* use correct PYPI_TOKEN environment variable ([d45a096](https://github.com/OtherVibes/mcp-as-a-judge/commit/d45a096773c28a9edc1e5e393d95c14687de467a))

## [0.1.6](https://github.com/hepivax/mcp-as-a-judge/compare/v0.1.5...v0.1.6) (2025-08-30)
## [0.1.6](https://github.com/OtherVibes/mcp-as-a-judge/compare/v0.1.5...v0.1.6) (2025-08-30)

### πŸ› Bug Fixes

* add PyPI publication to semantic-release ([bf47cdf](https://github.com/hepivax/mcp-as-a-judge/commit/bf47cdf66b177839f3b1bb0137b6b4a0973e98e7))
* add PyPI publication to semantic-release ([bf47cdf](https://github.com/OtherVibes/mcp-as-a-judge/commit/bf47cdf66b177839f3b1bb0137b6b4a0973e98e7))

## [0.1.5](https://github.com/hepivax/mcp-as-a-judge/compare/v0.1.4...v0.1.5) (2025-08-30)
## [0.1.5](https://github.com/OtherVibes/mcp-as-a-judge/compare/v0.1.4...v0.1.5) (2025-08-30)

### πŸ› Bug Fixes

* test conventional commit format ([e19e40e](https://github.com/hepivax/mcp-as-a-judge/commit/e19e40ede5b848f939a41391d06b54fcdeb680b1))
* test conventional commit format ([e19e40e](https://github.com/OtherVibes/mcp-as-a-judge/commit/e19e40ede5b848f939a41391d06b54fcdeb680b1))

# Changelog

Expand Down
9 changes: 9 additions & 0 deletions config.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
{
"database": {
"url": "sqlite://:memory:",
"max_context_records": 20,
"context_enrichment_count": 10,
"record_retention_days": 1
},
"enable_llm_fallback": true
}
3 changes: 2 additions & 1 deletion pyproject.toml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
[project]
name = "mcp-as-a-judge"
version = "0.1.0"
version = "0.2.0"
description = "🚨 MCP as a Judge: Prevent bad coding practices with AI-powered evaluation and user-driven decision making"
readme = "README.md"
license = { text = "MIT" }
Expand Down Expand Up @@ -32,6 +32,7 @@ dependencies = [
"pydantic>=2.0.0",
"jinja2>=3.1.0",
"litellm>=1.0.0",
"sqlmodel>=0.0.24",
]

[project.urls]
Expand Down
146 changes: 146 additions & 0 deletions src/mcp_as_a_judge/config.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,146 @@
"""
Configuration management for MCP as a Judge.

This module handles loading and managing configuration from various sources
including config files, environment variables, and defaults.
"""

import json
import os
from pathlib import Path

from pydantic import BaseModel, Field

from .models import DatabaseConfig


class Config(BaseModel):
"""Main configuration model for the application."""

database: DatabaseConfig = Field(default_factory=DatabaseConfig)
enable_llm_fallback: bool = Field(
default=True,
description="Whether to enable LLM fallback when MCP sampling is not available",
)


def load_config(config_path: str | None = None) -> Config:
"""
Load configuration from file and environment variables.

Args:
config_path: Path to config file. If None, looks for config.json in current directory

Returns:
Config object with loaded settings
"""
# Default configuration
config_data = {}

# Try to load from config file
if config_path is None:
config_path = "config.json"

config_file = Path(config_path)
if config_file.exists():
try:
with open(config_file) as f:
config_data = json.load(f)
except (json.JSONDecodeError, OSError) as e:
print(f"Warning: Could not load config file {config_path}: {e}")

# Override with environment variables if present
db_provider = os.getenv("MCP_JUDGE_DB_PROVIDER")
if db_provider:
if "database" not in config_data:
config_data["database"] = {}
config_data["database"]["provider"] = db_provider

db_url = os.getenv("MCP_JUDGE_DB_URL")
if db_url:
if "database" not in config_data:
config_data["database"] = {}
config_data["database"]["url"] = db_url

max_context = os.getenv("MCP_JUDGE_MAX_CONTEXT_RECORDS")
if max_context:
if "database" not in config_data:
config_data["database"] = {}
try:
config_data["database"]["max_context_records"] = int(max_context)
except ValueError:
print(
f"Warning: Invalid value for MCP_JUDGE_MAX_CONTEXT_RECORDS: {max_context}"
)

llm_fallback = os.getenv("MCP_JUDGE_ENABLE_LLM_FALLBACK")
if llm_fallback:
config_data["enable_llm_fallback"] = llm_fallback.lower() in (
"true",
"1",
"yes",
"on",
)

return Config(**config_data)


def create_default_config_file(config_path: str = "config.json") -> None:
"""
Create a default configuration file.

Args:
config_path: Path where to create the config file
"""
default_config = {
"database": {"provider": "in_memory", "url": "", "max_context_records": 10},
"enable_llm_fallback": True,
}

with open(config_path, "w") as f:
json.dump(default_config, f, indent=2)

print(f"Created default configuration file: {config_path}")


def get_database_provider_from_url(url: str) -> str:
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

let's remove this method - the url should be hardcoded for now.

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

from url that is hard code i extract if its sqllite regular or in memory

"""
Determine database provider from URL.

Args:
url: Database connection URL

Returns:
Provider name based on URL scheme

Examples:
"" or None -> "in_memory" (SQLite in-memory)
"sqlite://:memory:" -> "in_memory" (SQLite in-memory)
"sqlite:///path/to/file.db" -> "sqlite" (SQLite file)
"postgresql://..." -> "postgresql"
"mysql://..." -> "mysql"
"""
if not url or url.strip() == "":
return "in_memory"

url_lower = url.lower().strip()

# SQLite in-memory
if url_lower == "sqlite://:memory:" or url_lower == ":memory:":
return "in_memory"

# SQLite file
elif url_lower.startswith("sqlite://") or url_lower.endswith(".db"):
return "sqlite"

# PostgreSQL
elif url_lower.startswith("postgresql://") or url_lower.startswith("postgres://"):
return "postgresql"

# MySQL
elif url_lower.startswith("mysql://") or url_lower.startswith("mysql+"):
return "mysql"

else:
# Default to in_memory for unknown URLs
return "in_memory"
18 changes: 18 additions & 0 deletions src/mcp_as_a_judge/db/__init__.py
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

rename the package to memory

Copy link
Collaborator Author

@doriwal doriwal Sep 7, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

why, its storage that can be in memory and can be regular , i think db is a good name for that

Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
"""
Database abstraction layer for MCP as a Judge.

This module provides database interfaces and providers for storing
conversation history and tool interactions.
"""

from .factory import DatabaseFactory, create_database_provider
from .interface import ConversationHistoryDB, ConversationRecord
from .providers import SQLiteProvider

__all__ = [
"ConversationHistoryDB",
"ConversationRecord",
"DatabaseFactory",
"SQLiteProvider",
"create_database_provider",
]
Loading
Loading