Skip to content

fix: FastMCP v3 tag filtering and run_args UnboundLocalError in server setup#249

Merged
bashandbone merged 2 commits intoclaude/issue-237-20260317-0019from
copilot/sub-pr-239
Mar 17, 2026
Merged

fix: FastMCP v3 tag filtering and run_args UnboundLocalError in server setup#249
bashandbone merged 2 commits intoclaude/issue-237-20260317-0019from
copilot/sub-pr-239

Conversation

Copy link
Contributor

Copilot AI commented Mar 17, 2026

FastMCP v3 removed include_tags/exclude_tags as FastMCP() constructor parameters, causing errors when settings (which include these as computed fields) were passed directly. Additionally, run_args was only assigned in the else branch of create_stdio_server, producing an UnboundLocalError when settings provided a mcp_server key.

Changes

  • _setup_server: Pop include_tags and exclude_tags from mutable_args before FastMCP() construction; apply via the v3 visibility API post-construction:

    include_tags = mutable_args.pop("include_tags", None)
    exclude_tags = mutable_args.pop("exclude_tags", None)
    # ...
    app = FastMCP("CodeWeaver", **mutable_args)
    if exclude_tags:
        app.disable(tags=exclude_tags)
    if include_tags:
        app.enable(tags=include_tags, only=True)
  • create_stdio_server: Move run_args extraction outside the if/else so it always reads from http_settings regardless of which branch populates it.


🔒 GitHub Advanced Security automatically protects Copilot coding agent pull requests. You can protect all pull requests by enabling Advanced Security for your repositories. Learn more about Advanced Security.

…n server setup

Co-authored-by: bashandbone <89049923+bashandbone@users.noreply.github.com>
Copilot AI changed the title [WIP] [237] Migrate CodeWeaver from FastMCP v2 to v3 fix: FastMCP v3 tag filtering and run_args UnboundLocalError in server setup Mar 17, 2026
Copilot AI requested a review from bashandbone March 17, 2026 17:39
@bashandbone bashandbone marked this pull request as ready for review March 17, 2026 18:38
Copilot AI review requested due to automatic review settings March 17, 2026 18:38
Copy link
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull request overview

Updates CodeWeaver’s MCP server integration to accommodate FastMCP v3 API changes (tag filtering + stdio proxy setup) and prevents a stdio server setup crash caused by an uninitialized run_args.

Changes:

  • Update _setup_server to remove include_tags/exclude_tags from FastMCP constructor args and apply tag visibility via app.disable() / app.enable().
  • Fix create_stdio_server so run_args is always derived from http_settings regardless of which settings branch is taken.
  • Bump FastMCP and related dependency lock entries; minor unit-test import reformatting.

Reviewed changes

Copilot reviewed 4 out of 5 changed files in this pull request and generated 1 comment.

Show a summary per file
File Description
src/codeweaver/server/mcp/server.py FastMCP v3 tag filtering changes + stdio proxy run_args initialization fix
uv.lock Dependency lock updates (FastMCP >=3) and transitive dependency changes
tests/unit/test_main.py Import formatting only
tests/unit/core/types/test_embedding_batch_info_intent.py Import formatting only
tests/unit/core/types/test_chunk_embeddings_properties.py Import formatting only
Comments suppressed due to low confidence (2)

src/codeweaver/server/mcp/server.py:316

  • run_args can be None if it comes from an unvalidated FastMcpServerSettingsDict (e.g., user config sets run_args: null). In that case setup_runargs(run_args, ...) will raise because it expects a mapping. Consider normalizing right after popping (e.g., run_args = mutable_args.pop("run_args") or {}) and/or validating into FastMcpHttpRunArgs before calling setup_runargs.
    run_args = mutable_args.pop("run_args", {})
    # Remove transport from args - it's not a FastMCP constructor parameter
    mutable_args.pop("transport", None)
    # FastMCP v3: include_tags/exclude_tags are no longer constructor parameters.
    # Extract them here and apply via app.enable()/app.disable() after construction.
    include_tags: set[str] | None = mutable_args.pop("include_tags", None)
    exclude_tags: set[str] | None = mutable_args.pop("exclude_tags", None)

    # Always use default middleware classes for this transport
    from codeweaver.server.mcp.middleware import default_middleware_for_transport

    middleware = default_middleware_for_transport(transport)

    if is_http:
        run_args = setup_runargs(run_args, host, port, verbose=verbose, debug=debug)
    app = FastMCP(

src/codeweaver/server/mcp/server.py:333

  • include_tags / exclude_tags are removed from mutable_args and never passed into CwMcpHttpState.from_app(...), so CwMcpHttpState.mcp_settings will no longer reflect these settings (it is built from the kwargs in from_app when instructions is present). Consider adding these keys back into the kwargs passed to from_app so the state object still contains the full FastMcpServerSettingsDict (even if FastMCP v3 no longer accepts them in the constructor).
    # FastMCP v3: Apply tag-based visibility filtering using the new enable()/disable() API
    if exclude_tags:
        app.disable(tags=exclude_tags)
    if include_tags:
        app.enable(tags=include_tags, only=True)
    if is_http:
        from codeweaver.server.mcp.state import CwMcpHttpState

        # Pass the instantiated middleware from app.middleware, not the classes
        return CwMcpHttpState.from_app(
            app, **(mutable_args | {"run_args": run_args, "middleware": app.middleware})
        )

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

else:
http_settings = _get_fastmcp_settings_map(http=True)
run_args = http_settings.get("run_args", {})
run_args = http_settings.get("run_args", {})
Copy link
Contributor

@github-actions github-actions bot left a comment

Choose a reason for hiding this comment

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

Code Review: FastMCP v3 Migration

This PR successfully addresses the FastMCP v3 migration issues. The changes are well-implemented and follow the correct migration pattern.

✅ Positive Aspects

  1. Correct API Migration: The tag filtering migration from constructor parameters to post-construction methods is correct:

    • Properly extracts include_tags and exclude_tags before FastMCP construction
    • Applies them via the new app.disable() and app.enable() API after instantiation
    • Uses only=True for allowlist behavior with include_tags, which matches the v3 pattern
  2. Fixed UnboundLocalError: The run_args fix in create_stdio_server is correct:

    • Moved from inside the else block to after the if/else, ensuring it's always defined
    • This prevents the UnboundLocalError when settings contains mcp_server
  3. Good Documentation: Clear inline comments explain the v3 API changes

  4. Dependency Update: uv.lock shows FastMCP upgraded from 2.14.5 to 3.1.1, and removed unused dependencies (cloudpickle, croniter, diskcache, fakeredis, lupa)

🔍 Minor Observations

  1. Import Order Changes: The test file import reordering (moving local imports after third-party) and blank line additions are style improvements, though unrelated to the core fix. These follow PEP 8 conventions, which is good.

  2. Lock File Changes: The uv.lock changes include:

    • Removal of several unused packages (cloudpickle, croniter, diskcache, fakeredis, lupa)
    • Addition of aiofile, caio (new FastMCP v3 dependencies)
    • Addition of opentelemetry-api, uncalled-for, watchfiles, pyyaml (new FastMCP v3 features)
  3. Type Annotations: The code correctly types include_tags and exclude_tags as set[str] | None

🤔 Questions/Suggestions

  1. Testing: Are there existing tests that cover tag filtering behavior? It would be good to ensure that:

    • Tools/resources with exclude_tags are properly hidden
    • Tools/resources with include_tags are properly exposed
    • The allowlist behavior with only=True works as expected
  2. Computed Fields: I noticed that include_tags and exclude_tags are defined as computed fields in src/codeweaver/server/config/settings.py. These computed fields return the tags as sets, which matches the expected type for the v3 API.

✅ Verdict

The implementation is correct and addresses the stated issues. The code properly migrates from FastMCP v2 to v3 patterns. CI checks are pending, but the code changes look solid.

Recommendation: Approve once CI passes, assuming there are no test failures.

@bashandbone bashandbone merged commit 702912c into claude/issue-237-20260317-0019 Mar 17, 2026
12 checks passed
@bashandbone bashandbone deleted the copilot/sub-pr-239 branch March 17, 2026 19:13
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants