Skip to content

Commit bb2c32c

Browse files
Release v1.1.6: update server.json for MCP Registry and refine spatial tools
- Sync server.json version to 1.1.6, add title field for MCP Registry - Unify parameter defaults and top-k utility in spatial tools
1 parent ffd93c1 commit bb2c32c

7 files changed

Lines changed: 49 additions & 5 deletions

File tree

chatspatial/__init__.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@
55
Integrates 60 methods from Python and R ecosystems via Model Context Protocol.
66
"""
77

8-
__version__ = "1.1.5"
8+
__version__ = "1.1.6"
99

1010
# Import configuration to set up environment
1111
from . import config as config # noqa: F401

chatspatial/models/data.py

Lines changed: 17 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@
66

77
from typing import Annotated, Literal, Optional, Union
88

9-
from pydantic import BaseModel, ConfigDict, Field, model_validator
9+
from pydantic import BaseModel, ConfigDict, Field, field_validator, model_validator
1010
from typing_extensions import Self
1111

1212
# =============================================================================
@@ -1445,6 +1445,22 @@ class SpatialVariableGenesParameters(BaseModel):
14451445
)
14461446
warn_housekeeping: bool = True # Warn if >30% of top genes are housekeeping genes
14471447

1448+
@field_validator("n_top_genes")
1449+
@classmethod
1450+
def validate_n_top_genes(cls, v: int | None) -> int | None:
1451+
if v is not None and v <= 0:
1452+
raise ValueError("n_top_genes must be positive")
1453+
return v
1454+
1455+
@field_validator("sparkx_percentage")
1456+
@classmethod
1457+
def validate_sparkx_percentage(cls, v: float) -> float:
1458+
if not (0 < v < 1):
1459+
raise ValueError(
1460+
"sparkx_percentage must be between 0 and 1"
1461+
)
1462+
return v
1463+
14481464

14491465
class CellCommunicationParameters(BaseModel):
14501466
"""Cell-cell communication analysis parameters model with explicit user control"""

chatspatial/tools/spatial_domains.py

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,13 +8,16 @@
88
function, which handles data preparation and dispatches to the selected method.
99
"""
1010

11+
import logging
1112
from collections import Counter
1213
from typing import TYPE_CHECKING, Any
1314

1415
import numpy as np
1516
import pandas as pd
1617
import scanpy as sc
1718

19+
logger = logging.getLogger(__name__)
20+
1821
if TYPE_CHECKING:
1922
from ..spatial_mcp_adapter import ToolContext
2023

@@ -90,6 +93,12 @@ async def identify_spatial_domains(
9093

9194
# Step 1: Determine gene subset (no copy yet)
9295
use_hvg = params.use_highly_variable and "highly_variable" in adata.var.columns
96+
if params.use_highly_variable and "highly_variable" not in adata.var.columns:
97+
logger.warning(
98+
"use_highly_variable=True but 'highly_variable' "
99+
"column not found in adata.var. "
100+
"Using all genes instead."
101+
)
93102
hvg_mask = adata.var["highly_variable"] if use_hvg else None
94103

95104
# Step 2: Check data quality on original adata (read-only)

chatspatial/tools/spatial_genes.py

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -72,6 +72,14 @@ def _calculate_sparse_gene_stats(X) -> tuple[np.ndarray, np.ndarray]:
7272
gene_totals = np.asarray(X.sum(axis=0)).flatten()
7373
n_expressed = np.asarray((X > 0).sum(axis=0)).flatten()
7474

75+
# Guard against NaN/Inf values from degenerate inputs
76+
gene_totals = np.nan_to_num(
77+
gene_totals, nan=0.0, posinf=0.0, neginf=0.0
78+
)
79+
n_expressed = np.nan_to_num(
80+
n_expressed, nan=0.0, posinf=0.0, neginf=0.0
81+
)
82+
7583
return gene_totals, n_expressed
7684

7785

chatspatial/utils/compute.py

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -423,6 +423,16 @@ def gmm_clustering(
423423
# Fit and predict
424424
labels = gmm.fit_predict(data)
425425

426+
if not gmm.converged_:
427+
import warnings
428+
429+
warnings.warn(
430+
f"GMM did not converge after {gmm.n_iter_} iterations. "
431+
"Results may be unreliable. Consider increasing max_iter.",
432+
UserWarning,
433+
stacklevel=2,
434+
)
435+
426436
# Convert to 1-indexed labels (mclust compatibility)
427437
# mclust returns labels starting from 1, sklearn from 0
428438
labels = labels + 1

pyproject.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
44

55
[project]
66
name = "chatspatial"
7-
version = "1.1.5"
7+
version = "1.1.6"
88
description = "ChatSpatial: Natural language-driven spatial transcriptomics analysis via Model Context Protocol (MCP) integration"
99
readme = "README.md"
1010
license = {text = "MIT"}

server.json

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,17 +1,18 @@
11
{
22
"$schema": "https://static.modelcontextprotocol.io/schemas/2025-12-11/server.schema.json",
33
"name": "io.github.cafferychen777/chatspatial",
4+
"title": "ChatSpatial",
45
"description": "Natural language-driven spatial transcriptomics analysis with 60+ methods via MCP",
56
"repository": {
67
"url": "https://github.com/cafferychen777/ChatSpatial",
78
"source": "github"
89
},
9-
"version": "1.0.3",
10+
"version": "1.1.6",
1011
"packages": [
1112
{
1213
"registryType": "pypi",
1314
"identifier": "chatspatial",
14-
"version": "1.0.3",
15+
"version": "1.1.6",
1516
"transport": {
1617
"type": "stdio"
1718
},

0 commit comments

Comments
 (0)