Skip to content

feat(server): restore dependencies parameter on MCPServer#2358

Open
maxisbey wants to merge 1 commit intomainfrom
restore-dependencies-param
Open

feat(server): restore dependencies parameter on MCPServer#2358
maxisbey wants to merge 1 commit intomainfrom
restore-dependencies-param

Conversation

@maxisbey
Copy link
Contributor

Restores the dependencies parameter that was removed in #1877, pending a proper design decision on its future (tracked in #2354).

Motivation and Context

The dependencies parameter is consumed by mcp dev and mcp install to auto-populate uv run --with <pkg> flags when launching servers or writing Claude Desktop config. Removing it without a working replacement creates two problems:

  1. Breaks high-profile users — awslabs/mcp (8.5k★, 47 server files), mindsdb (38.8k★), redis/mcp-redis all use this parameter. When jlowin's fastmcp package removed the same parameter, it triggered 8+ breakage issues across the ecosystem.

  2. No working replacement — the examples were migrated to PEP 723 inline script metadata, but mcp install/mcp dev can't read it. uv only parses PEP 723 when the script is the direct target; the CLI wraps it in mcp run <file>, so the metadata is ignored.

The CLI consumer code at cli.py#L261 and cli.py#L451 still checks for server.dependencies via hasattr/getattr — it was never removed, so this restoration makes those checks functional again.

Long-term options (deprecate → PEP 723, adopt a config file like FastMCP 2.0, or keep as-is) are laid out in #2354.

How Has This Been Tested?

Added test_dependencies verifying the parameter round-trips through both mcp.dependencies and mcp.settings.dependencies, and defaults to [] when omitted. All 88 tests in tests/server/mcpserver/test_server.py pass.

Breaking Changes

None — this restores previously-removed API.

Types of changes

  • Bug fix (non-breaking change which fixes an issue)
  • New feature (non-breaking change which adds functionality)
  • Breaking change (fix or feature that would cause existing functionality to change)
  • Documentation update

Checklist

  • I have read the MCP Documentation
  • My code follows the repository's style guidelines
  • New and existing tests pass locally
  • I have added appropriate error handling
  • I have added or updated documentation as needed

Additional context

Closes the gap left by #1877. See #2354 for the design discussion.

AI Disclaimer

Restores the `dependencies` parameter that was removed in #1877. The
parameter is read by the `mcp dev` and `mcp install` CLI commands to
auto-populate `uv run --with <pkg>` flags.

Removal without a working replacement breaks high-profile consumers
(awslabs/mcp uses it in 47 servers, mindsdb, redis/mcp-redis). While
PEP 723 inline script metadata is the intended replacement, the CLI
doesn't currently parse it — `uv` only reads PEP 723 when the script
is the direct target, not when wrapped in `mcp run <file>`.

Long-term design (deprecate vs. keep vs. config file) is tracked in
the linked issue.

Github-Issue:#2354
Copy link
Contributor

@claude claude bot left a comment

Choose a reason for hiding this comment

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

This reverses the deliberate removal from #1877 and is a design decision that a maintainer should confirm, even though the code change itself is small and correct. The nit about Collection[str] accepting bare strings is worth addressing too.

Extended reasoning...

Overview

This PR restores the dependencies parameter on MCPServer that was removed in #1877. It adds a dependencies: list[str] field to Settings, a dependencies: Collection[str] = () constructor parameter, and a simple test. The CLI consumer code in cli.py already reads server.dependencies via hasattr/getattr, so this restoration makes those checks functional again.

Security risks

No direct security risks. The dependencies values are passed as --with flags to uv run, which installs packages from PyPI. This is existing behavior in the CLI and not introduced by this PR.

Level of scrutiny

This deserves maintainer-level scrutiny despite being small. The parameter was deliberately removed in #1877, and restoring it is a design decision about the SDK's API surface. The PR description acknowledges this is a stopgap pending a design discussion in #2354. A maintainer should confirm they want to take this approach rather than one of the alternatives outlined in that issue.

Other factors

The bug report about Collection[str] accepting bare strings is a valid nit — MCPServer("test", dependencies="pandas") would silently produce ["p", "a", "n", "d", "a", "s"]. Changing to list[str] (consistent with other parameters in the same constructor) or adding a runtime guard would prevent this footgun. The test coverage is adequate for the happy path but does not cover this edge case.

warn_on_duplicate_resources: bool = True,
warn_on_duplicate_tools: bool = True,
warn_on_duplicate_prompts: bool = True,
dependencies: Collection[str] = (),
Copy link
Contributor

Choose a reason for hiding this comment

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

🟡 Collection[str] accepts a bare str (since str is itself a collection of single-char strings), so MCPServer("test", dependencies="pandas") silently produces ["p", "a", "n", "d", "a", "s"] via the list(dependencies) call. Consider changing to list[str] or adding if isinstance(dependencies, str): raise TypeError(...) to catch this footgun.

Extended reasoning...

The Bug

The dependencies parameter on line 148 is typed as Collection[str], but Python's str type satisfies Collection[str] — a string is iterable and yields single-character strings. This means MCPServer("test", dependencies="pandas") passes type checking (mypy/pyright will not flag it) and also passes pydantic validation at runtime.

How It Manifests

On line 158, list(dependencies) is called to convert the collection to a list. When dependencies is the string "pandas", this produces ["p", "a", "n", "d", "a", "s"] instead of the intended ["pandas"]. The value is then stored in self.settings.dependencies and self.dependencies.

Downstream Impact

The CLI consumer code in cli.py:262 and cli.py:451-453 reads server.dependencies and passes the values as --with package names to uv. With the character-split list, uv would attempt to install packages named p, a, n, d, a, s — which would either fail with confusing errors or, worse, install unintended packages if single-letter package names happen to exist on PyPI.

Step-by-Step Proof

  1. User writes: mcp = MCPServer("my-server", dependencies="pandas")
  2. __init__ receives dependencies = "pandas" (a str, which is a valid Collection[str])
  3. Line 158 executes list("pandas")["p", "a", "n", "d", "a", "s"]
  4. self.dependencies is set to ["p", "a", "n", "d", "a", "s"]
  5. mcp dev or mcp install reads server.dependencies and builds uv run --with p --with a --with n --with d --with a --with s

Fix

The simplest fix is to change Collection[str] to list[str] on line 148 (and update the default from () to []). This would cause type checkers to flag dependencies="pandas" as an error. Alternatively, keep Collection[str] for flexibility but add a runtime guard: if isinstance(dependencies, str): raise TypeError("dependencies must be a list of strings, not a bare string").

Note that every other list parameter in the same constructor (e.g., tools: list[Tool] | None, icons: list[Icon] | None) already uses list[T] directly, so using list[str] would be consistent with the existing API style.

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.

1 participant