mirror of
https://github.com/semantica-agi/semantica.git
synced 2026-08-29 04:26:20 +00:00
fix(mcp): use semantica.__version__ as authoritative MCP version source
The previous implementation used importlib.metadata.version('semantica') as
the primary version source with a PackageNotFoundError fallback to
semantica.__version__. This caused two of the three new regression tests to
fail in editable/development installs, where dist-info (egg-info) is written
at install time and is not automatically updated on subsequent version bumps.
In this repo, pyproject.toml declares version as a static field (not dynamic),
and semantica/__init__.py maintains __version__ in sync with it by convention.
semantica.__version__ is therefore the authoritative source of truth and is
always present whenever semantica.mcp_server is importable -- the importlib
.metadata indirection adds no value and can return a stale value.
Changes:
- semantica/mcp_server/__init__.py: replace the importlib.metadata try/except
block with a direct 'from semantica import __version__ as _SEMANTICA_VERSION'
- tests/test_mcp_server_version.py: rewrite tests to assert both MCP version
surfaces (SERVER_INFO['version'] and semantica://schema/info) against
semantica.__version__ as the single ground truth; add 0.4.0 regression
canaries and a cross-surface consistency assertion; remove the mirrored
importlib.metadata resolution that masked the staleness problem
The root-level mcp/ directory (a separate unpublished companion implementation
not included in the built package) is intentionally left unchanged -- it is
outside the scope of issue #863 which targets the semantica-mcp entry point.
This commit is contained in:
@@ -45,14 +45,16 @@ import json
|
||||
import logging
|
||||
import os
|
||||
import sys
|
||||
from importlib.metadata import PackageNotFoundError, version
|
||||
from typing import Any
|
||||
|
||||
try:
|
||||
_SEMANTICA_VERSION = version("semantica")
|
||||
except PackageNotFoundError:
|
||||
# Preserve direct source-tree execution when distribution metadata is absent.
|
||||
from semantica import __version__ as _SEMANTICA_VERSION
|
||||
# `semantica.__version__` is the authoritative package version — it is kept in
|
||||
# sync with pyproject.toml's static `version` field by the release process and
|
||||
# is always present whenever this submodule is importable. Using it directly
|
||||
# is simpler and more reliable than `importlib.metadata.version("semantica")`,
|
||||
# which reads dist-info written at install time and can lag the source in
|
||||
# editable installs (egg-info / dist-info is not regenerated on every version
|
||||
# bump, so it can reflect a stale value).
|
||||
from semantica import __version__ as _SEMANTICA_VERSION
|
||||
|
||||
# ── logging ────────────────────────────────────────────────────────────────
|
||||
_log_level = getattr(logging, os.environ.get("SEMANTICA_LOG_LEVEL", "WARNING").upper(), logging.WARNING)
|
||||
|
||||
@@ -1,35 +1,93 @@
|
||||
"""Regression tests for MCP server version reporting."""
|
||||
"""Regression tests for MCP server version reporting (issue #863).
|
||||
|
||||
Both public MCP version surfaces must derive from the same authoritative
|
||||
package version rather than a hardcoded stale literal:
|
||||
1. MCP ``initialize`` → ``serverInfo.version``
|
||||
2. ``semantica://schema/info`` → ``version``
|
||||
|
||||
The authoritative source of truth is ``semantica.__version__``, which is
|
||||
maintained in sync with ``pyproject.toml``'s static ``version`` field by
|
||||
the release process. We assert equality against that value rather than
|
||||
duplicating the version-resolution logic here, so the tests remain valid
|
||||
through future version bumps without modification.
|
||||
|
||||
The ``assertNotEqual(..., "0.4.0")`` canaries guard against regression to
|
||||
the original stale literal that triggered issue #863.
|
||||
"""
|
||||
|
||||
import unittest
|
||||
from importlib.metadata import PackageNotFoundError, version
|
||||
|
||||
import semantica
|
||||
from semantica import mcp_server
|
||||
|
||||
_EXPECTED = semantica.__version__
|
||||
|
||||
|
||||
class TestMCPServerVersion(unittest.TestCase):
|
||||
def test_server_info_uses_distribution_version(self):
|
||||
try:
|
||||
expected = version("semantica")
|
||||
except PackageNotFoundError:
|
||||
expected = semantica.__version__
|
||||
|
||||
self.assertEqual(mcp_server.SERVER_INFO["version"], expected)
|
||||
# ------------------------------------------------------------------ #
|
||||
# SERVER_INFO (used directly in the initialize response)
|
||||
# ------------------------------------------------------------------ #
|
||||
|
||||
def test_initialize_reports_package_version(self):
|
||||
def test_server_info_version_matches_package(self):
|
||||
"""SERVER_INFO['version'] must equal the authoritative package version."""
|
||||
self.assertEqual(mcp_server.SERVER_INFO["version"], _EXPECTED)
|
||||
|
||||
def test_server_info_version_is_not_stale_literal(self):
|
||||
"""Guard: SERVER_INFO must not report the original hardcoded 0.4.0."""
|
||||
self.assertNotEqual(mcp_server.SERVER_INFO["version"], "0.4.0")
|
||||
|
||||
# ------------------------------------------------------------------ #
|
||||
# MCP initialize → serverInfo.version
|
||||
# ------------------------------------------------------------------ #
|
||||
|
||||
def test_initialize_server_info_version_matches_package(self):
|
||||
"""The MCP initialize response must report the authoritative package version."""
|
||||
response = mcp_server._handle(
|
||||
{"jsonrpc": "2.0", "id": 1, "method": "initialize"}
|
||||
)
|
||||
|
||||
self.assertIsNotNone(response)
|
||||
self.assertEqual(
|
||||
response["result"]["serverInfo"]["version"], semantica.__version__
|
||||
response["result"]["serverInfo"]["version"],
|
||||
_EXPECTED,
|
||||
)
|
||||
|
||||
def test_schema_info_resource_reports_package_version(self):
|
||||
resource = mcp_server._read_resource("semantica://schema/info")
|
||||
def test_initialize_server_info_version_is_not_stale_literal(self):
|
||||
"""Guard: initialize must not report the original hardcoded 0.4.0."""
|
||||
response = mcp_server._handle(
|
||||
{"jsonrpc": "2.0", "id": 1, "method": "initialize"}
|
||||
)
|
||||
self.assertNotEqual(response["result"]["serverInfo"]["version"], "0.4.0")
|
||||
|
||||
self.assertEqual(resource["version"], semantica.__version__)
|
||||
# ------------------------------------------------------------------ #
|
||||
# semantica://schema/info → version
|
||||
# ------------------------------------------------------------------ #
|
||||
|
||||
def test_schema_info_resource_version_matches_package(self):
|
||||
"""The semantica://schema/info resource must report the authoritative package version."""
|
||||
resource = mcp_server._read_resource("semantica://schema/info")
|
||||
self.assertEqual(resource["version"], _EXPECTED)
|
||||
|
||||
def test_schema_info_resource_version_is_not_stale_literal(self):
|
||||
"""Guard: schema/info must not report the original hardcoded 0.4.0."""
|
||||
resource = mcp_server._read_resource("semantica://schema/info")
|
||||
self.assertNotEqual(resource["version"], "0.4.0")
|
||||
|
||||
# ------------------------------------------------------------------ #
|
||||
# Both surfaces must agree
|
||||
# ------------------------------------------------------------------ #
|
||||
|
||||
def test_both_version_surfaces_are_identical(self):
|
||||
"""SERVER_INFO and schema/info must report the exact same version string,
|
||||
confirming both surfaces derive from a single authoritative value."""
|
||||
init_response = mcp_server._handle(
|
||||
{"jsonrpc": "2.0", "id": 1, "method": "initialize"}
|
||||
)
|
||||
schema_resource = mcp_server._read_resource("semantica://schema/info")
|
||||
self.assertEqual(
|
||||
init_response["result"]["serverInfo"]["version"],
|
||||
schema_resource["version"],
|
||||
)
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
|
||||
Reference in New Issue
Block a user