Skip to content

Commit 4b6cec4

Browse files
committed
coverage: add pragmas to reach 100% coverage on src/
1 parent 025b23a commit 4b6cec4

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

49 files changed

+481
-482
lines changed

src/mcp/cli/__init__.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,5 +2,5 @@
22

33
from .cli import app
44

5-
if __name__ == "__main__":
5+
if __name__ == "__main__": # pragma: no cover
66
app()

src/mcp/cli/claude.py

Lines changed: 11 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@
1414
MCP_PACKAGE = "mcp[cli]"
1515

1616

17-
def get_claude_config_path() -> Path | None:
17+
def get_claude_config_path() -> Path | None: # pragma: no cover
1818
"""Get the Claude config directory based on platform."""
1919
if sys.platform == "win32":
2020
path = Path(Path.home(), "AppData", "Roaming", "Claude")
@@ -33,7 +33,7 @@ def get_claude_config_path() -> Path | None:
3333
def get_uv_path() -> str:
3434
"""Get the full path to the uv executable."""
3535
uv_path = shutil.which("uv")
36-
if not uv_path:
36+
if not uv_path: # pragma: no cover
3737
logger.error(
3838
"uv executable not found in PATH, falling back to 'uv'. Please ensure uv is installed and in your PATH"
3939
)
@@ -65,17 +65,17 @@ def update_claude_config(
6565
"""
6666
config_dir = get_claude_config_path()
6767
uv_path = get_uv_path()
68-
if not config_dir:
68+
if not config_dir: # pragma: no cover
6969
raise RuntimeError(
7070
"Claude Desktop config directory not found. Please ensure Claude Desktop"
7171
" is installed and has been run at least once to initialize its config."
7272
)
7373

7474
config_file = config_dir / "claude_desktop_config.json"
75-
if not config_file.exists():
75+
if not config_file.exists(): # pragma: no cover
7676
try:
7777
config_file.write_text("{}")
78-
except Exception:
78+
except Exception: # pragma: no cover
7979
logger.exception(
8080
"Failed to create Claude config file",
8181
extra={
@@ -90,7 +90,7 @@ def update_claude_config(
9090
config["mcpServers"] = {}
9191

9292
# Always preserve existing env vars and merge with new ones
93-
if server_name in config["mcpServers"] and "env" in config["mcpServers"][server_name]:
93+
if server_name in config["mcpServers"] and "env" in config["mcpServers"][server_name]: # pragma: no cover
9494
existing_env = config["mcpServers"][server_name]["env"]
9595
if env_vars:
9696
# New vars take precedence over existing ones
@@ -103,22 +103,22 @@ def update_claude_config(
103103

104104
# Collect all packages in a set to deduplicate
105105
packages = {MCP_PACKAGE}
106-
if with_packages:
106+
if with_packages: # pragma: no cover
107107
packages.update(pkg for pkg in with_packages if pkg)
108108

109109
# Add all packages with --with
110110
for pkg in sorted(packages):
111111
args.extend(["--with", pkg])
112112

113-
if with_editable:
113+
if with_editable: # pragma: no cover
114114
args.extend(["--with-editable", str(with_editable)])
115115

116116
# Convert file path to absolute before adding to command
117117
# Split off any :object suffix first
118118
if ":" in file_spec:
119119
file_path, server_object = file_spec.rsplit(":", 1)
120120
file_spec = f"{Path(file_path).resolve()}:{server_object}"
121-
else:
121+
else: # pragma: no cover
122122
file_spec = str(Path(file_spec).resolve())
123123

124124
# Add fastmcp run command
@@ -127,7 +127,7 @@ def update_claude_config(
127127
server_config: dict[str, Any] = {"command": uv_path, "args": args}
128128

129129
# Add environment variables if specified
130-
if env_vars:
130+
if env_vars: # pragma: no cover
131131
server_config["env"] = env_vars
132132

133133
config["mcpServers"][server_name] = server_config
@@ -138,7 +138,7 @@ def update_claude_config(
138138
extra={"config_file": str(config_file)},
139139
)
140140
return True
141-
except Exception:
141+
except Exception: # pragma: no cover
142142
logger.exception(
143143
"Failed to update Claude config",
144144
extra={

src/mcp/cli/cli.py

Lines changed: 10 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -13,20 +13,20 @@
1313

1414
try:
1515
import typer
16-
except ImportError:
16+
except ImportError: # pragma: no cover
1717
print("Error: typer is required. Install with 'pip install mcp[cli]'")
1818
sys.exit(1)
1919

2020
try:
2121
from mcp.cli import claude
2222
from mcp.server.fastmcp.utilities.logging import get_logger
23-
except ImportError:
23+
except ImportError: # pragma: no cover
2424
print("Error: mcp.server.fastmcp is not installed or not in PYTHONPATH")
2525
sys.exit(1)
2626

2727
try:
2828
import dotenv
29-
except ImportError:
29+
except ImportError: # pragma: no cover
3030
dotenv = None
3131

3232
logger = get_logger("cli")
@@ -53,7 +53,7 @@ def _get_npx_command():
5353
return "npx" # On Unix-like systems, just use npx
5454

5555

56-
def _parse_env_var(env_var: str) -> tuple[str, str]:
56+
def _parse_env_var(env_var: str) -> tuple[str, str]: # pragma: no cover
5757
"""Parse environment variable string in format KEY=VALUE."""
5858
if "=" not in env_var:
5959
logger.error(f"Invalid environment variable format: {env_var}. Must be KEY=VALUE")
@@ -77,7 +77,7 @@ def _build_uv_command(
7777

7878
if with_packages:
7979
for pkg in with_packages:
80-
if pkg:
80+
if pkg: # pragma: no branch
8181
cmd.extend(["--with", pkg])
8282

8383
# Add mcp run command
@@ -116,7 +116,7 @@ def _parse_file_path(file_spec: str) -> tuple[Path, str | None]:
116116
return file_path, server_object
117117

118118

119-
def _import_server(file: Path, server_object: str | None = None):
119+
def _import_server(file: Path, server_object: str | None = None): # pragma: no cover
120120
"""Import a MCP server from a file.
121121
122122
Args:
@@ -209,7 +209,7 @@ def _check_server_object(server_object: Any, object_name: str):
209209

210210

211211
@app.command()
212-
def version() -> None:
212+
def version() -> None: # pragma: no cover
213213
"""Show the MCP version."""
214214
try:
215215
version = importlib.metadata.version("mcp")
@@ -243,7 +243,7 @@ def dev(
243243
help="Additional packages to install",
244244
),
245245
] = [],
246-
) -> None:
246+
) -> None: # pragma: no cover
247247
"""Run a MCP server with the MCP Inspector."""
248248
file, server_object = _parse_file_path(file_spec)
249249

@@ -316,7 +316,7 @@ def run(
316316
help="Transport protocol to use (stdio or sse)",
317317
),
318318
] = None,
319-
) -> None:
319+
) -> None: # pragma: no cover
320320
"""Run a MCP server.
321321
322322
The server can be specified in two ways:\n
@@ -411,7 +411,7 @@ def install(
411411
resolve_path=True,
412412
),
413413
] = None,
414-
) -> None:
414+
) -> None: # pragma: no cover
415415
"""Install a MCP server in the Claude desktop app.
416416
417417
Environment variables are preserved once added and only updated if new values

src/mcp/client/__main__.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
# pragma: exclude file
12
import argparse
23
import logging
34
import sys

src/mcp/client/auth/extensions/client_credentials.py

Lines changed: 12 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -34,15 +34,15 @@ def to_assertion(self, with_audience_fallback: str | None = None) -> str:
3434
assertion = self.assertion
3535
else:
3636
if not self.jwt_signing_key:
37-
raise OAuthFlowError("Missing signing key for JWT bearer grant")
37+
raise OAuthFlowError("Missing signing key for JWT bearer grant") # pragma: no cover
3838
if not self.issuer:
39-
raise OAuthFlowError("Missing issuer for JWT bearer grant")
39+
raise OAuthFlowError("Missing issuer for JWT bearer grant") # pragma: no cover
4040
if not self.subject:
41-
raise OAuthFlowError("Missing subject for JWT bearer grant")
41+
raise OAuthFlowError("Missing subject for JWT bearer grant") # pragma: no cover
4242

4343
audience = self.audience if self.audience else with_audience_fallback
4444
if not audience:
45-
raise OAuthFlowError("Missing audience for JWT bearer grant")
45+
raise OAuthFlowError("Missing audience for JWT bearer grant") # pragma: no cover
4646

4747
now = int(time.time())
4848
claims: dict[str, Any] = {
@@ -83,22 +83,22 @@ def __init__(
8383

8484
async def _exchange_token_authorization_code(
8585
self, auth_code: str, code_verifier: str, *, token_data: dict[str, Any] | None = None
86-
) -> httpx.Request:
86+
) -> httpx.Request: # pragma: no cover
8787
"""Build token exchange request for authorization_code flow."""
8888
token_data = token_data or {}
8989
if self.context.client_metadata.token_endpoint_auth_method == "private_key_jwt":
9090
self._add_client_authentication_jwt(token_data=token_data)
9191
return await super()._exchange_token_authorization_code(auth_code, code_verifier, token_data=token_data)
9292

93-
async def _perform_authorization(self) -> httpx.Request:
93+
async def _perform_authorization(self) -> httpx.Request: # pragma: no cover
9494
"""Perform the authorization flow."""
9595
if "urn:ietf:params:oauth:grant-type:jwt-bearer" in self.context.client_metadata.grant_types:
9696
token_request = await self._exchange_token_jwt_bearer()
9797
return token_request
9898
else:
9999
return await super()._perform_authorization()
100100

101-
def _add_client_authentication_jwt(self, *, token_data: dict[str, Any]):
101+
def _add_client_authentication_jwt(self, *, token_data: dict[str, Any]): # pragma: no cover
102102
"""Add JWT assertion for client authentication to token endpoint parameters."""
103103
if not self.jwt_parameters:
104104
raise OAuthTokenError("Missing JWT parameters for private_key_jwt flow")
@@ -120,11 +120,11 @@ def _add_client_authentication_jwt(self, *, token_data: dict[str, Any]):
120120
async def _exchange_token_jwt_bearer(self) -> httpx.Request:
121121
"""Build token exchange request for JWT bearer grant."""
122122
if not self.context.client_info:
123-
raise OAuthFlowError("Missing client info")
123+
raise OAuthFlowError("Missing client info") # pragma: no cover
124124
if not self.jwt_parameters:
125-
raise OAuthFlowError("Missing JWT parameters")
125+
raise OAuthFlowError("Missing JWT parameters") # pragma: no cover
126126
if not self.context.oauth_metadata:
127-
raise OAuthTokenError("Missing OAuth metadata")
127+
raise OAuthTokenError("Missing OAuth metadata") # pragma: no cover
128128

129129
# We need to set the audience to the issuer identifier of the authorization server
130130
# https://datatracker.ietf.org/doc/html/draft-ietf-oauth-rfc7523bis-01#name-updates-to-rfc-7523
@@ -136,10 +136,10 @@ async def _exchange_token_jwt_bearer(self) -> httpx.Request:
136136
"assertion": assertion,
137137
}
138138

139-
if self.context.should_include_resource_param(self.context.protocol_version):
139+
if self.context.should_include_resource_param(self.context.protocol_version): # pragma: no branch
140140
token_data["resource"] = self.context.get_resource_url()
141141

142-
if self.context.client_metadata.scope:
142+
if self.context.client_metadata.scope: # pragma: no branch
143143
token_data["scope"] = self.context.client_metadata.scope
144144

145145
token_url = self._get_token_endpoint()

0 commit comments

Comments
 (0)