Skip to content

Refactor transform list methods to pure function pattern#2942

Merged
jlowin merged 3 commits intomainfrom
refactor-transform-list-methods-to-pure-functions
Jan 19, 2026
Merged

Refactor transform list methods to pure function pattern#2942
jlowin merged 3 commits intomainfrom
refactor-transform-list-methods-to-pure-functions

Conversation

@jlowin
Copy link
Copy Markdown
Member

@jlowin jlowin commented Jan 19, 2026

Refactors transform list methods (list_tools, list_resources, list_resource_templates, list_prompts) from middleware pattern to pure function pattern.

Changes

List methods now receive sequences directly instead of call_next callables:

# Before (middleware pattern)
async def list_tools(self, call_next: ListToolsNext) -> Sequence[Tool]:
    tools = await call_next()
    return transformed_tools

# After (pure function pattern)
async def list_tools(self, tools: Sequence[Tool]) -> Sequence[Tool]:
    return transformed_tools

Providers apply transforms sequentially instead of building middleware chains:

# Before
chain = base
for transform in self.transforms:
    chain = partial(transform.list_tools, call_next=chain)
return await chain()

# After
tools = await self._list_tools()
for transform in self.transforms:
    tools = await transform.list_tools(tools)
return tools

Impact

  • Simpler API: List methods are now pure functions, easier to understand and test
  • Better performance: No function call overhead from middleware chain
  • Consistent pattern: List operations use pure functions, get operations keep middleware pattern for routing flexibility

Get methods (get_tool, get_resource, etc.) remain unchanged and continue using the middleware pattern, which is necessary for name/URI transformation and routing.

Change list_tools, list_resources, list_resource_templates, and list_prompts from middleware pattern (call_next) to pure function pattern (receive sequences directly). Get methods remain in middleware pattern.
@jlowin jlowin added the enhancement Improvement to existing functionality. For issues and smaller PR improvements. label Jan 19, 2026
@marvin-context-protocol marvin-context-protocol Bot added server Related to FastMCP server implementation or server-side functionality. tests labels Jan 19, 2026
@coderabbitai
Copy link
Copy Markdown
Contributor

coderabbitai Bot commented Jan 19, 2026

Note

Other AI code review bot(s) detected

CodeRabbit has detected other AI code review bot(s) in this pull request and will avoid duplicating their findings in the review comments. This may lead to a less comprehensive review.

Walkthrough

This PR refactors list operations (list_tools, list_resources, list_resource_templates, list_prompts) from a call_next/middleware chain to a pure-function style: list methods now accept and return sequences directly. Providers and server code that previously built per-type call_next chains were simplified to iteratively apply each transform to the current sequences. ListXNext type aliases and their usages were removed; get operations retain the middleware call_next pattern.

Possibly related PRs

  • PR 2836: Introduced the original call_next-based middleware transform system that this change converts to sequence-based list transforms.
  • PR 2913: Modifies provider and wrapped provider transform chaining behavior with the same sequential list transformation approach.
  • PR 2912: Updates the transforms list_* API and related Enabled/visibility transform plumbing to the new sequence-parameter pattern.
🚥 Pre-merge checks | ✅ 2 | ❌ 1
❌ Failed checks (1 warning)
Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 79.07% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (2 passed)
Check name Status Explanation
Title check ✅ Passed The title clearly and concisely summarizes the main change: refactoring transform list methods to use a pure function pattern instead of middleware.
Description check ✅ Passed The description is comprehensive and follows the template structure with clear sections, code examples, and impact analysis, though some checklist items are unchecked.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing touches
  • 📝 Generate docstrings

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

Copy link
Copy Markdown

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 47626b9ece

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread src/fastmcp/server/transforms/__init__.py
Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 0

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
src/fastmcp/server/providers/base.py (1)

439-474: Fix get_tasks list transform chaining (runtime TypeError).
Line 461 currently partials transform.list_* with call_next, but list_* no longer accepts that argument. This will throw at runtime when task registration runs.

🛠️ Proposed fix (align with pure-sequence list_* APIs)
-        # Apply provider's own transforms to components using the chain pattern
-        # For tasks, we need the fully-transformed names, so use the list_ chain
-        # Note: We build mini-chains for each component type
-
-        async def tools_base() -> Sequence[Tool]:
-            return tools
-
-        async def resources_base() -> Sequence[Resource]:
-            return resources
-
-        async def templates_base() -> Sequence[ResourceTemplate]:
-            return templates
-
-        async def prompts_base() -> Sequence[Prompt]:
-            return prompts
-
-        # Apply transforms in order
-        tools_chain = tools_base
-        resources_chain = resources_base
-        templates_chain = templates_base
-        prompts_chain = prompts_base
-
-        for transform in self.transforms:
-            tools_chain = partial(transform.list_tools, call_next=tools_chain)
-            resources_chain = partial(
-                transform.list_resources, call_next=resources_chain
-            )
-            templates_chain = partial(
-                transform.list_resource_templates, call_next=templates_chain
-            )
-            prompts_chain = partial(transform.list_prompts, call_next=prompts_chain)
-
-        transformed_tools = await tools_chain()
-        transformed_resources = await resources_chain()
-        transformed_templates = await templates_chain()
-        transformed_prompts = await prompts_chain()
+        # Apply provider's own transforms in order (pure list transforms)
+        transformed_tools = tools
+        transformed_resources = resources
+        transformed_templates = templates
+        transformed_prompts = prompts
+
+        for transform in self.transforms:
+            transformed_tools = await transform.list_tools(transformed_tools)
+            transformed_resources = await transform.list_resources(transformed_resources)
+            transformed_templates = await transform.list_resource_templates(
+                transformed_templates
+            )
+            transformed_prompts = await transform.list_prompts(transformed_prompts)

- Update transforms.mdx to document new list method signatures
- Fix Provider.get_tasks() which still used old call_next pattern
@jlowin jlowin merged commit 4d2feb0 into main Jan 19, 2026
11 checks passed
@jlowin jlowin deleted the refactor-transform-list-methods-to-pure-functions branch January 19, 2026 21:21
gfortaine pushed a commit to gfortaine/fastmcp that referenced this pull request Jan 30, 2026
gfortaine pushed a commit to gfortaine/fastmcp that referenced this pull request Feb 4, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

enhancement Improvement to existing functionality. For issues and smaller PR improvements. server Related to FastMCP server implementation or server-side functionality. tests

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant