Files
basicmachines-co-basic-memory/tests/mcp/test_tool_contracts.py
2026-05-11 12:56:26 -05:00

157 lines
4.2 KiB
Python

"""Tool contract tests for MCP tool signatures."""
from __future__ import annotations
import inspect
from collections.abc import Callable
from typing import Any, cast
from basic_memory.mcp import tools
EXPECTED_TOOL_SIGNATURES: dict[str, list[str]] = {
"build_context": [
"url",
"project",
"project_id",
"depth",
"timeframe",
"page",
"page_size",
"max_related",
"output_format",
],
"canvas": ["nodes", "edges", "title", "directory", "project", "project_id"],
"cloud_info": [],
"create_memory_project": [
"project_name",
"project_path",
"set_default",
"workspace",
"output_format",
],
"delete_note": ["identifier", "is_directory", "project", "project_id", "output_format"],
"delete_project": ["project_name", "workspace"],
"edit_note": [
"identifier",
"operation",
"content",
"project",
"workspace",
"project_id",
"section",
"find_text",
"expected_replacements",
"output_format",
],
"fetch": ["id"],
"list_directory": ["dir_name", "depth", "file_name_glob", "project", "project_id"],
"list_memory_projects": ["output_format"],
"list_workspaces": ["output_format"],
"move_note": [
"identifier",
"destination_path",
"destination_folder",
"is_directory",
"project",
"project_id",
"output_format",
],
"read_content": ["path", "project", "project_id"],
"read_note": [
"identifier",
"project",
"project_id",
"output_format",
"include_frontmatter",
],
"release_notes": [],
"recent_activity": [
"type",
"depth",
"timeframe",
"page",
"page_size",
"project",
"project_id",
"output_format",
],
"schema_diff": ["note_type", "project", "project_id", "output_format"],
"schema_infer": ["note_type", "threshold", "project", "project_id", "output_format"],
"schema_validate": ["note_type", "identifier", "project", "project_id", "output_format"],
"search": ["query"],
"search_notes": [
"query",
"project",
"project_id",
"search_all_projects",
"page",
"page_size",
"search_type",
"output_format",
"note_types",
"entity_types",
"after_date",
"metadata_filters",
"tags",
"status",
"min_similarity",
],
"view_note": ["identifier", "project", "project_id"],
"write_note": [
"title",
"content",
"directory",
"project",
"project_id",
"tags",
"note_type",
"metadata",
"overwrite",
"output_format",
],
}
TOOL_FUNCTIONS: dict[str, object] = {
"build_context": tools.build_context,
"canvas": tools.canvas,
"cloud_info": tools.cloud_info,
"create_memory_project": tools.create_memory_project,
"delete_note": tools.delete_note,
"delete_project": tools.delete_project,
"edit_note": tools.edit_note,
"fetch": tools.fetch,
"list_directory": tools.list_directory,
"list_memory_projects": tools.list_memory_projects,
"list_workspaces": tools.list_workspaces,
"move_note": tools.move_note,
"read_content": tools.read_content,
"read_note": tools.read_note,
"release_notes": tools.release_notes,
"recent_activity": tools.recent_activity,
"schema_diff": tools.schema_diff,
"schema_infer": tools.schema_infer,
"schema_validate": tools.schema_validate,
"search": tools.search,
"search_notes": tools.search_notes,
"view_note": tools.view_note,
"write_note": tools.write_note,
}
def _signature_params(tool_obj: object) -> list[str]:
params = []
for param in inspect.signature(cast(Callable[..., Any], tool_obj)).parameters.values():
if param.name == "context":
continue
params.append(param.name)
return params
def test_mcp_tool_signatures_are_stable():
assert set(TOOL_FUNCTIONS.keys()) == set(EXPECTED_TOOL_SIGNATURES.keys())
for tool_name, tool_obj in TOOL_FUNCTIONS.items():
assert _signature_params(tool_obj) == EXPECTED_TOOL_SIGNATURES[tool_name]