Skip to main content
Glama
watamoo

Crossword MCP Server

by watamoo

search_consistent_sets

Find crossword puzzle solutions by identifying consistent word assignments that satisfy all crossing conditions from registered candidates.

Instructions

登録済み候補から交差条件を満たす割当てを探索する。

Args: target_clue_ids (list[str] | None): 探索対象とするカギ ID のリスト。None または 空リストを渡した場合は、候補が登録済みのすべてのカギを対象とする。

Returns: list[dict[str, str]]: 整合性が取れた解集合のリスト。各要素は clue_id をキー、 採用した候補語を値とする辞書。複数の最大解が存在する場合は重複しない 形で列挙し、整合するカギが 1 件も無い場合は空リストを返す。

Raises: RuntimeError: setup が未実行、または候補語が一件も登録されていない場合。 KeyError: target_clue_ids に含まれる ID がカギ定義または候補登録に存在しない 場合。

Input Schema

TableJSON Schema
NameRequiredDescriptionDefault
target_clue_idsNo

Output Schema

TableJSON Schema
NameRequiredDescriptionDefault
resultYes

Implementation Reference

  • Main handler for the 'search_consistent_sets' tool. Validates inputs, prepares target clues and candidates, and calls the _solve helper to find consistent assignments via backtracking.
    async def search_consistent_sets(target_clue_ids: list[str] | None = None) -> list[dict[str, str]]:
        """登録済み候補から交差条件を満たす割当てを探索する。
    
        Args:
            target_clue_ids (list[str] | None): 探索対象とするカギ ID のリスト。`None` または
                空リストを渡した場合は、候補が登録済みのすべてのカギを対象とする。
    
        Returns:
            list[dict[str, str]]: 整合性が取れた解集合のリスト。各要素は `clue_id` をキー、
                採用した候補語を値とする辞書。複数の最大解が存在する場合は重複しない
                形で列挙し、整合するカギが 1 件も無い場合は空リストを返す。
    
        Raises:
            RuntimeError: `setup` が未実行、または候補語が一件も登録されていない場合。
            KeyError: `target_clue_ids` に含まれる ID がカギ定義または候補登録に存在しない
                場合。
        """
    
        _ensure_setup()
    
        if not state.candidates:
            raise RuntimeError("register_candidates を先に呼び出して候補ワードを登録してください。")
    
        if target_clue_ids is None:
            target_ids = list(state.candidates.keys())
        else:
            target_ids = [cid.strip() for cid in target_clue_ids if cid and cid.strip()]
            if not target_ids:
                target_ids = list(state.candidates.keys())
    
        unique_ids = list(dict.fromkeys(target_ids))
    
        target_info: list[tuple[str, tuple[tuple[int, int], ...], list[str]]] = []
        for clue_id in unique_ids:
            if clue_id not in state.clues:
                raise KeyError(f"clue_id={clue_id} のカギが存在しません。")
            if clue_id not in state.candidates:
                raise KeyError(f"clue_id={clue_id} の候補が登録されていません。")
    
            clue = state.clues[clue_id]
            candidates = state.candidates[clue_id]
            target_info.append((clue_id, clue.positions, candidates))
    
        return _solve(target_info)
  • Helper function implementing the backtracking algorithm to find all maximum consistent sets of word assignments that satisfy crossword intersection constraints.
    def _solve(target_info: list[tuple[str, tuple[tuple[int, int], ...], list[str]]]) -> list[dict[str, str]]:
        "候補語を総当たりして交差一致を判定し、最大数のカギが一致する割当てを収集する"
        cell_letters: dict[tuple[int, int], str] = {}
        assignments: dict[str, str] = {}
        best_assignments: list[dict[str, str]] = []
        best_size = 0
        signatures: set[tuple[tuple[str, str], ...]] = set()
    
        def update_best() -> None:
            nonlocal best_size
            current_size = len(assignments)
            signature = tuple(sorted(assignments.items()))
            if current_size > best_size:
                best_size = current_size
                best_assignments.clear()
                signatures.clear()
            if current_size == best_size and signature not in signatures:
                best_assignments.append(dict(assignments))
                signatures.add(signature)
    
        def backtrack(index: int) -> None:
            if index == len(target_info):
                update_best()
                return
    
            clue_id, positions, candidates = target_info[index]
    
            for word in candidates:
                conflict = False
                placed: list[tuple[int, int]] = []
    
                for (row, col), char in zip(positions, word):
                    existing = cell_letters.get((row, col))
                    if existing is not None and existing != char:
                        conflict = True
                        break
    
                if conflict:
                    continue
    
                assignments[clue_id] = word
    
                for (row, col), char in zip(positions, word):
                    if (row, col) not in cell_letters:
                        cell_letters[(row, col)] = char
                        placed.append((row, col))
    
                backtrack(index + 1)
    
                for cell in placed:
                    del cell_letters[cell]
    
                del assignments[clue_id]
    
            backtrack(index + 1)
    
        backtrack(0)
    
        if best_size == 0:
            return []
    
        return best_assignments
Behavior4/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

With no annotations provided, the description carries the full burden and does well by disclosing key behavioral traits: it explains the return format (list of dicts with clue_id and candidate word), error conditions (raises RuntimeError for uninitialized setup or no candidates, KeyError for invalid IDs), and edge cases (empty list for no consistent clues, enumerates multiple maximum solutions without duplicates). This covers critical operational aspects beyond basic functionality.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness4/5

Is the description appropriately sized, front-loaded, and free of redundancy?

The description is well-structured with clear sections (Args, Returns, Raises) and front-loaded purpose statement. It's appropriately sized, with each sentence adding value: the opening explains the core function, and subsequent parts detail inputs, outputs, and errors without redundancy. Minor room for improvement in flow keeps it from a perfect score.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness5/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

Given the complexity (search tool with dependencies, error handling), no annotations, and an output schema present, the description is complete. It covers purpose, parameter semantics, return values, error conditions, and prerequisites. The output schema means return values don't need explanation, and the description adequately addresses all other contextual aspects for effective tool use.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters4/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema description coverage is 0%, so the description must compensate. It adds meaningful semantics for the single parameter 'target_clue_ids': explains it's a list of clue IDs or None, clarifies that None or empty list targets all registered clues, and notes validation (raises KeyError for non-existent IDs). This goes beyond the schema's basic type definition, providing context and usage rules.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose4/5

Does the description clearly state what the tool does and how it differs from similar tools?

The description clearly states the tool's purpose: '探索する' (explore/search) for '割当て' (assignments) that satisfy '交差条件' (intersection conditions) from '登録済み候補' (registered candidates). It specifies the resource (candidate assignments) and verb (search/explore). However, it doesn't explicitly differentiate from sibling tools like 'get_candidates' or 'render_solution', which keeps it from a perfect score.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines3/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

The description implies usage by mentioning prerequisites ('setup' must be executed, candidates must be registered) and dependencies on other tools. It also hints at alternatives by noting that 'target_clue_ids' can be None to target all clues. However, it lacks explicit guidance on when to use this tool versus siblings like 'get_candidates' or 'render_solution', leaving some ambiguity.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

Install Server

Other Tools

Latest Blog Posts

MCP directory API

We provide all the information about MCP servers via our MCP API.

curl -X GET 'https://glama.ai/api/mcp/v1/servers/watamoo/mcp-crossword-tools'

If you have feedback or need assistance with the MCP directory API, please join our Discord server