Skip to content
Merged
Show file tree
Hide file tree
Changes from all 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
7 changes: 5 additions & 2 deletions amorphouspy_api/src/amorphouspy_api/mcp_server.py
Original file line number Diff line number Diff line change
Expand Up @@ -28,8 +28,9 @@
1. `submit_job` — submit a simulation (returns job ID + URLs).
2. `get_job_status` — poll until status is "completed".
3. `get_job_results` — retrieve analysis data.
4. `search_jobs` — find existing results for similar compositions.
5. `list_glasses` / `lookup_glass` — browse available compositions.
4. `get_job_settings` — inspect the original submission parameters.
5. `search_jobs` — find existing results for similar compositions.
6. `list_glasses` / `lookup_glass` — browse available compositions.
"""

mcp = FastMCP(
Expand All @@ -51,6 +52,7 @@ def register_tools() -> None:
from amorphouspy_api.routers.jobs import (
cancel_job,
get_job_results,
get_job_settings,
get_job_status,
get_single_result,
search_jobs,
Expand All @@ -62,6 +64,7 @@ def register_tools() -> None:
search_jobs,
get_job_status,
cancel_job,
get_job_settings,
get_job_results,
get_single_result,
list_glasses,
Expand Down
10 changes: 10 additions & 0 deletions amorphouspy_api/src/amorphouspy_api/models.py
Original file line number Diff line number Diff line change
Expand Up @@ -487,6 +487,16 @@ class JobStatusResponse(BaseModel):
)


class JobSettingsResponse(BaseModel):
"""Response for ``GET /jobs/{id}/settings``."""

job_id: str
settings: dict = Field(
...,
description="Original submission parameters (composition, potential, simulation, analyses, electrostatics, tags).",
)


class JobResultsResponse(BaseModel):
"""Response for ``GET /jobs/{id}/results``."""

Expand Down
19 changes: 19 additions & 0 deletions amorphouspy_api/src/amorphouspy_api/routers/jobs.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@
POST /jobs:search - search jobs across all statuses
GET /jobs/{id} - poll job status
POST /jobs/{id}:cancel - cancel a running job
GET /jobs/{id}/settings - original submission settings
GET /jobs/{id}/results - all analysis results
GET /jobs/{id}/results/{analysis} - single analysis result
GET /jobs/{id}/structure - export quenched structure
Expand Down Expand Up @@ -40,6 +41,7 @@
JobSearchMatch,
JobSearchRequest,
JobSearchResponse,
JobSettingsResponse,
JobStatus,
JobStatusResponse,
JobSubmission,
Expand Down Expand Up @@ -379,6 +381,23 @@ def update_tags(job_id: str, body: TagsUpdate) -> TagsResponse:
return TagsResponse(job_id=job_id, tags=sorted(set(body.tags)))


@router.get("/{job_id}/settings", response_model=JobSettingsResponse)
def get_job_settings(job_id: str) -> JobSettingsResponse:
"""Return the original submission settings for a job."""
store = get_job_store()
job = store.get_job(job_id)
if not job:
raise HTTPException(status_code=404, detail="Job not found")

if not job.request_data:
raise HTTPException(status_code=404, detail="No settings stored for this job")

return JobSettingsResponse(
job_id=job.job_id,
settings=job.request_data,
)


@router.get("/{job_id}/results", response_model=JobResultsResponse)
def get_job_results(job_id: str) -> JobResultsResponse:
"""All completed analysis results for a job."""
Expand Down
36 changes: 36 additions & 0 deletions amorphouspy_api/src/tests/test_jobs.py
Original file line number Diff line number Diff line change
Expand Up @@ -309,6 +309,42 @@ def test_get_results_no_data() -> None:
assert resp.status_code == 404


# ---------------------------------------------------------------------------
# GET /jobs/{id}/settings
# ---------------------------------------------------------------------------


def test_get_settings_completed() -> None:
_insert_completed_job("j-settings-1")

resp = client.get("/jobs/j-settings-1/settings")
assert resp.status_code == 200
data = resp.json()
assert data["job_id"] == "j-settings-1"
assert "composition" in data["settings"]
assert "potential" in data["settings"]


def test_get_settings_not_found() -> None:
resp = client.get("/jobs/nonexistent/settings")
assert resp.status_code == 404


def test_get_settings_no_request_data() -> None:
store = get_job_store()
store.create_job(
Job(
job_id="j-no-settings",
request_hash="nosettings",
composition="SiO2 100",
potential="pmmcs",
status="completed",
)
)
resp = client.get("/jobs/j-no-settings/settings")
assert resp.status_code == 404


# ---------------------------------------------------------------------------
# GET /jobs/{id}/results/{analysis}
# ---------------------------------------------------------------------------
Expand Down
Loading