Skip to main content
Glama

permutations

Read-only

Calculate the number of ordered arrangements of k items chosen from n distinct items without repetition.

Instructions

Calculate the number of ways to choose k items from n items without repetition and with order.

Input Schema

TableJSON Schema
NameRequiredDescriptionDefault
nYesThe number of items to choose from.
kNoThe optional number of items to choose.

Output Schema

TableJSON Schema
NameRequiredDescriptionDefault
resultYes

Implementation Reference

  • The 'permutations' handler function. Calculates the number of ways to choose k items from n items without repetition and with order (P(n,k)). Uses math.perm(n,k). If k is None, defaults to n (full permutation). Raises McpError if k > n.
    async def permutations(
        self,
        ctx: Context,
        n: Annotated[
            int,
            Field(
                ge=1,
                description="The number of items to choose from.",
            ),
        ],
        k: Annotated[
            int | None,
            Field(
                default=None,
                ge=1,
                description="The optional number of items to choose.",
            ),
        ],
    ) -> int:
        """Calculate the number of ways to choose k items from n items without repetition and with order."""
        """If k is not provided, it defaults to n."""
        assert isinstance(n, int) and n >= 1, "n must be a positive integer."
    
        if k is None:
            k = n
        if k > n:
            raise McpError(
                error=ErrorData(
                    code=INVALID_PARAMS,
                    message=f"k ({k}) cannot be greater than n ({n}).",
                )
            )
    
        return math.perm(n, k)
  • Registration metadata for the 'permutations' tool in the PyMCP class. Declares the function name, tags (math, permutation, example), and annotations (readOnlyHint: True).
    {
        "fn": "permutations",
        "tags": ["math", "permutation", "example"],
        "annotations": {"readOnlyHint": True},
    },
  • The 'permutations' tool is included in the response caching middleware's deterministic tools list, alongside 'greet'. This means its results are cached.
    call_tool_settings=CallToolSettings(
        included_tools=["greet", "permutations"],
        ttl=EnvVars.RESPONSE_CACHE_TTL,
        enabled=EnvVars.RESPONSE_CACHE_TTL > 0,
    ),
  • The MCPMixin.register_features method iterates over the 'tools' list and registers each function (including 'permutations') with the FastMCP instance using the fn name and metadata.
    def register_features(self, mcp: FastMCP) -> FastMCP:
        """Register tools, resources, and prompts with the given FastMCP instance.
    
        Args:
            mcp (FastMCP): The FastMCP instance to register features with.
    
        Returns:
            FastMCP: The FastMCP instance with registered features.
        """
        # Register tools
        for tool in self.tools:
            assert "fn" in tool, "Tool metadata must include the 'fn' key."
            tool_copy = copy.deepcopy(tool)
            fn_name = tool_copy.pop("fn")
            fn = getattr(self, fn_name)
            mcp.tool(**tool_copy)(fn)  # pass remaining metadata as kwargs
        # Register resources
        for res in self.resources:
            assert "fn" in res and "uri" in res, "Resource metadata must include 'fn' and 'uri' keys."
            res_copy = copy.deepcopy(res)
            fn_name = res_copy.pop("fn")
            uri = res_copy.pop("uri")
            fn = getattr(self, fn_name)
            mcp.resource(uri, **res_copy)(fn)
        # Register prompts
        for pr in self.prompts:
            assert "fn" in pr, "Prompt metadata must include the 'fn' key."
            pr_copy = copy.deepcopy(pr)
            fn_name = pr_copy.pop("fn")
            fn = getattr(self, fn_name)
            mcp.prompt(**pr_copy)(fn)
    
        return mcp
    
    def get_tool_result(self, result: Any, metadata: dict[str, Any] | None = None) -> ToolResult:  # pragma: no cover
        """Create a ToolResult object with the given result and metadata, including package metadata.
    
        Args:
            result (Any): The result to include in the ToolResult.
            metadata (Dict[str, Any] | None, optional): Additional metadata to include. Defaults to None.
    
        Returns:
            ToolResult: The ToolResult object containing the result and metadata.
        """
        return ToolResult(
            structured_content={"result": result} if not isinstance(result, dict) else result,
            meta=metadata if metadata is not None else None,
        )
  • The Base64EncodedBinaryDataResponse model used for binary data responses (not directly used by permutations, but part of the server response infrastructure). The permutations tool returns a plain int directly, not using this model.
    class Base64EncodedBinaryDataResponse(BaseModel):
        """A base64 encoded binary data for MCP response along with its cryptographic hash."""
    
        AVAILABLE_HASH_ALGORITHMS: ClassVar[list[str]] = list(hashlib.algorithms_available)
        AVAILABLE_HASH_ALGORITHMS_STR: ClassVar[str] = ""
        if not AVAILABLE_HASH_ALGORITHMS:  # pragma: no cover
            pass
        elif len(AVAILABLE_HASH_ALGORITHMS) == 1:  # pragma: no cover
            AVAILABLE_HASH_ALGORITHMS_STR = AVAILABLE_HASH_ALGORITHMS[0]
        elif len(AVAILABLE_HASH_ALGORITHMS) == 2:  # pragma: no cover
            AVAILABLE_HASH_ALGORITHMS_STR = " and ".join(AVAILABLE_HASH_ALGORITHMS)
        else:
            AVAILABLE_HASH_ALGORITHMS_STR = (
                ", ".join(AVAILABLE_HASH_ALGORITHMS[:-1]) + f", and {AVAILABLE_HASH_ALGORITHMS[-1]}"
            )
        # See https://docs.python.org/3/library/hashlib.html#shake-variable-length-digests
        SHAKE_DIGEST_LENGTH: ClassVar[int] = 32  # bytes
    
        data: Base64Bytes = Field(
            description="Base64 encoded binary data.",
        )
        hash: str = Field(
            description="A hexadecimal encoded of a hash of the binary data.",
        )
        hash_algorithm: str = Field(
            description=f"The algorithm used to compute the hash, e.g., 'sha3_512'. Available algorithms: {AVAILABLE_HASH_ALGORITHMS_STR}",
        )
    
        @model_validator(mode="after")
        def check_data_hash(self) -> "Base64EncodedBinaryDataResponse":
            if self.hash_algorithm not in Base64EncodedBinaryDataResponse.AVAILABLE_HASH_ALGORITHMS:
                raise ValueError(
                    f"Unsupported hash algorithm: {self.hash_algorithm}. Available algorithms: {Base64EncodedBinaryDataResponse.AVAILABLE_HASH_ALGORITHMS_STR}"
                )
            hasher = hashlib.new(self.hash_algorithm)
            hasher.update(self.data)
            computed_hash = (
                hasher.hexdigest()
                if not self.hash_algorithm.startswith("shake")
                # Make sure that for variable length hash algorithms, such as SHAKE128 and SHAKE256, we get a fixed length hash for testing
                else hasher.hexdigest(Base64EncodedBinaryDataResponse.SHAKE_DIGEST_LENGTH)  # ty: ignore[too-many-positional-arguments]
            )
            if computed_hash != self.hash:
                raise ValueError(f"Hash mismatch: provided hash {self.hash} does not match computed hash {computed_hash}.")
            return self
Behavior3/5

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

Annotations declare readOnlyHint=true; description adds that it calculates without repetition and with order. No mention of edge cases (e.g., k>n, k=null) or error handling. Basic behavioral traits disclosed but not exhaustive.

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

Conciseness5/5

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

Single sentence, 16 words, to the point. No redundant information.

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

Completeness4/5

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

Output schema exists; basic definition covers main purpose. Lacks details on return format or behavior for null k or k>n, but given tool simplicity, it's mostly complete.

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

Parameters3/5

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

Schema has 100% description coverage; description restates param purpose without adding formula or additional semantics. Baseline 3 is appropriate.

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

Purpose5/5

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

The description precisely defines permutations: order matters, no repetition. Verb 'Calculate' and resource 'number of permutations' are clear. Distinguishes from combinations and other combinatorial operations.

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?

Implied usage (when order matters, no repetition) but no explicit when-not-to-use or alternatives. Sibling tools are unrelated, so no confusion, but lack of guidance reduces score.

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/anirbanbasu/pymcp'

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