"""Configuration for the QDK/Chemistry MCP Server."""
# --------------------------------------------------------------------------------------------
# Copyright (c) Microsoft Corporation. All rights reserved.
# Licensed under the MIT License. See LICENSE.txt in the project root for license information.
# --------------------------------------------------------------------------------------------
import errno
import os
from pathlib import Path
from qdk_chemistry import __version__
[docs]
class QDKMCPConfig:
"""Configuration class for QDK/Chemistry MCP Server.
In general, the agent will work in a dedicated project directory,
where the directory structure is like:
scratch/projects/
├── project1/
│ ├── water.structure.json
│ ├── water.orbitals.json
│ └── water.wavefunction.json
├── project2/
│ ├── n2.structure.json
│ ├── n2.orbitals.json
│ └── n2.wavefunction.json
"""
[docs]
def __init__(self):
"""Initialize configuration with default values."""
default_scratch = Path("/scratch")
bckp_scratch = Path.home() / ".qdk_chem" / "scratch"
if "QDK_WORKSPACE_ROOT" in os.environ:
self.scratch_dir = Path(os.environ["QDK_WORKSPACE_ROOT"])
elif "QDK_SCRATCH_DIR" in os.environ:
self.scratch_dir = Path(os.environ["QDK_SCRATCH_DIR"])
else:
self.scratch_dir = default_scratch
self.projects_dir = self.scratch_dir / "projects"
# Local computation cache — configurable via QDK_CACHE_DIR.
# Defaults to <scratch>/cache. All algorithm results (local and
# remote) are persisted here so identical runs are never recomputed.
if "QDK_CACHE_DIR" in os.environ:
self.cache_dir = Path(os.environ["QDK_CACHE_DIR"])
else:
self.cache_dir = self.scratch_dir / "cache"
# Job files directory — configurable via QDK_JOBS_DIR.
# Defaults to <scratch>/jobs. Job files are named job_<id>.json
# and contain everything needed to check, cancel, or fetch results.
if "QDK_JOBS_DIR" in os.environ:
self.jobs_dir = Path(os.environ["QDK_JOBS_DIR"])
else:
self.jobs_dir = self.scratch_dir / "jobs"
# Server settings
self.server_name = "qdk-chem-mcp"
self.server_version = __version__
try:
self._setup_directories()
except OSError as error:
if error.errno not in (errno.EACCES, errno.EROFS):
raise
self.scratch_dir = bckp_scratch
self.projects_dir = self.scratch_dir / "projects"
if "QDK_CACHE_DIR" not in os.environ:
self.cache_dir = self.scratch_dir / "cache"
if "QDK_JOBS_DIR" not in os.environ:
self.jobs_dir = self.scratch_dir / "jobs"
self._setup_directories()
[docs]
def set_workspace_root(self, workspace_root: Path) -> None:
"""Move default project, cache, and job storage into a workspace.
Args:
workspace_root: Bound workspace directory used as the storage root.
Raises:
OSError: If the workspace storage directories cannot be created.
"""
projects_dir = workspace_root / "projects"
cache_dir = Path(os.environ["QDK_CACHE_DIR"]) if "QDK_CACHE_DIR" in os.environ else workspace_root / "cache"
jobs_dir = Path(os.environ["QDK_JOBS_DIR"]) if "QDK_JOBS_DIR" in os.environ else workspace_root / "jobs"
for directory in (workspace_root, projects_dir, cache_dir, jobs_dir):
directory.mkdir(parents=True, exist_ok=True)
self.scratch_dir = workspace_root
self.projects_dir = projects_dir
self.cache_dir = cache_dir
self.jobs_dir = jobs_dir
def _setup_directories(self):
"""Set up scratch and project directories."""
self.scratch_dir.mkdir(parents=True, exist_ok=True)
self.projects_dir.mkdir(parents=True, exist_ok=True)
self.cache_dir.mkdir(parents=True, exist_ok=True)
self.jobs_dir.mkdir(parents=True, exist_ok=True)
# Global configuration instance
config = QDKMCPConfig()