Tool() constructor server¶
Who this page is for: someone using the lower-level Server plus Tool(...) style instead of FastMCP.
What you will learn¶
- How mcpolish discovers tools registered through
Tool(name=, description=, inputSchema=). - Why explicit input schemas are required to set in this style.
- How to lint a typical low-level server.
Background¶
The official Python SDK ships two styles:
| Style | Class | Example |
|---|---|---|
| Decorator | FastMCP | @mcp.tool() on a function. |
| Constructor | Server + Tool(...) |
Hand-written list of Tool objects. |
mcpolish reads both. This page covers the constructor style.
Step by step¶
1. Write a constructor-style server¶
# ledger.py
from mcp import Server, Tool
server = Server("ledger")
TOOLS = [
Tool(
name="create_entry",
description=(
"Use this when the user reports a new transaction. "
"Returns the new entry id."
),
inputSchema={
"type": "object",
"properties": {
"amount_cents": {
"type": "integer",
"description": "Amount in cents. Example: 1299.",
"example": 1299,
},
"currency": {
"type": "string",
"description": "ISO 4217 code. Example: 'USD'.",
"example": "USD",
},
},
"required": ["amount_cents", "currency"],
},
),
]
2. Lint it¶
Expected:
3. Remove the required array on purpose¶
inputSchema={
"type": "object",
"properties": {
"amount_cents": {"type": "integer", "description": "Amount in cents."},
},
}
Re-lint. MP004 fires:
ledger.py:5:9: MP004 [W] tool `create_entry` inputSchema declares properties
['amount_cents'] but no `required` array. Add `required: []` even when empty
so agents can tell which params are mandatory.
Add "required": [] (or list the mandatory params) and MP004 stops firing.
What constructor style requires¶
The constructor style is more verbose by design. mcpolish needs:
nameset to a string literal.name=spec["name"]is dynamic and skipped.descriptionset to a string literal. mcpolish supports concatenated strings.inputSchemaset to a dict literal.
If any of these is computed at runtime, mcpolish cannot see the tool. See the dynamic registration scenario.
Schema authoring tips¶
The constructor style gives you full control over the input schema. mcpolish reads that schema directly, so:
- Adding an
examplefield to a property silences MP022 for that param. - Setting
"required": [...]silences MP004. - Setting
"type": "object"at the root silences MP005. - Using
"$ref"or"oneOf"is supported but the linter does not deeply inspect referenced subschemas.
Common variations¶
Adding tools through server.add_tool(...)¶
mcpolish also recognises:
Either inputSchema or input_schema is accepted. Same rule applies: the kwargs must be literal.
Multiple Tool() literals in one list¶
mcpolish picks up every literal Tool object in the file.
Troubleshooting¶
MP005 fires "inputSchema.type must be 'object'". The MCP spec requires the root of inputSchema to be an object. If you set type: "string" at the root, MP005 fires.
My description is in a constant and mcpolish does not see it. A constant reference (description=MY_DESC) is not a literal at the call site. mcpolish needs an inline string. Inline the description or use FastMCP plus a docstring.