Skip to content

Commit be2f1d4

Browse files
committed
add models and update imports
1 parent 254037a commit be2f1d4

File tree

7 files changed

+130
-22
lines changed

7 files changed

+130
-22
lines changed

src/mcp_agent/cli/auth/__init__.py

Lines changed: 14 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,18 @@
33
This package provides utilities for authentication (for now, api keys).
44
"""
55

6-
from .main import load_api_key_credentials, save_api_key_credentials
6+
from .main import (
7+
clear_credentials,
8+
load_api_key_credentials,
9+
load_credentials,
10+
save_credentials,
11+
)
12+
from .models import UserCredentials
713

8-
__all__ = ["load_api_key_credentials", "save_api_key_credentials"]
14+
__all__ = [
15+
"clear_credentials",
16+
"load_api_key_credentials",
17+
"load_credentials",
18+
"save_credentials",
19+
"UserCredentials",
20+
]
Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
11
"""Constants for the MCP Agent auth utilities."""
22

33
# Default values
4-
DEFAULT_CREDENTIALS_PATH = "~/.mcp_agent/cloud/auth/credentials"
4+
DEFAULT_CREDENTIALS_PATH = "~/.mcp-agent/credentials.json"

src/mcp_agent/cli/auth/main.py

Lines changed: 41 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,32 +1,64 @@
1+
import json
12
import os
23
from typing import Optional
34

45
from .constants import DEFAULT_CREDENTIALS_PATH
6+
from .models import UserCredentials
57

68

7-
def save_api_key_credentials(api_key: str):
8-
"""Save an API key to the credentials file.
9+
def save_credentials(credentials: UserCredentials) -> None:
10+
"""Save user credentials to the credentials file.
911
1012
Args:
11-
api_key: API key to persist
13+
credentials: UserCredentials object to persist
1214
1315
Returns:
1416
None
1517
"""
1618
credentials_path = os.path.expanduser(DEFAULT_CREDENTIALS_PATH)
1719
os.makedirs(os.path.dirname(credentials_path), exist_ok=True)
20+
21+
# Create file with restricted permissions (0600) to prevent leakage
1822
with open(credentials_path, "w", encoding="utf-8") as f:
19-
f.write(api_key)
23+
f.write(credentials.to_json())
24+
os.chmod(credentials_path, 0o600)
2025

2126

22-
def load_api_key_credentials() -> Optional[str]:
23-
"""Load an API key from the credentials file.
27+
def load_credentials() -> Optional[UserCredentials]:
28+
"""Load user credentials from the credentials file.
2429
2530
Returns:
26-
String. API key if it exists, None otherwise
31+
UserCredentials object if it exists, None otherwise
2732
"""
2833
credentials_path = os.path.expanduser(DEFAULT_CREDENTIALS_PATH)
2934
if os.path.exists(credentials_path):
30-
with open(credentials_path, "r", encoding="utf-8") as f:
31-
return f.read().strip()
35+
try:
36+
with open(credentials_path, "r", encoding="utf-8") as f:
37+
return UserCredentials.from_json(f.read())
38+
except (json.JSONDecodeError, KeyError, ValueError):
39+
# Handle corrupted or old format credentials
40+
return None
3241
return None
42+
43+
44+
def clear_credentials() -> bool:
45+
"""Clear stored credentials.
46+
47+
Returns:
48+
bool: True if credentials were cleared, False if none existed
49+
"""
50+
credentials_path = os.path.expanduser(DEFAULT_CREDENTIALS_PATH)
51+
if os.path.exists(credentials_path):
52+
os.remove(credentials_path)
53+
return True
54+
return False
55+
56+
57+
def load_api_key_credentials() -> Optional[str]:
58+
"""Load an API key from the credentials file (backward compatibility).
59+
60+
Returns:
61+
String. API key if it exists, None otherwise
62+
"""
63+
credentials = load_credentials()
64+
return credentials.api_key if credentials else None

src/mcp_agent/cli/auth/models.py

Lines changed: 64 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,64 @@
1+
"""Authentication models for MCP Agent Cloud CLI."""
2+
3+
import json
4+
from dataclasses import dataclass
5+
from datetime import datetime
6+
from typing import List, Optional
7+
8+
9+
@dataclass
10+
class UserCredentials:
11+
"""User authentication credentials and identity information."""
12+
13+
# Authentication
14+
api_key: str
15+
token_expires_at: Optional[datetime] = None
16+
17+
# Identity
18+
username: Optional[str] = None
19+
email: Optional[str] = None
20+
21+
@property
22+
def is_token_expired(self) -> bool:
23+
"""Check if the token is expired."""
24+
if not self.token_expires_at:
25+
return False
26+
return datetime.now() > self.token_expires_at
27+
28+
def to_dict(self) -> dict:
29+
"""Convert to dictionary for JSON serialization."""
30+
result = {
31+
"api_key": self.api_key,
32+
"username": self.username,
33+
"email": self.email,
34+
}
35+
36+
if self.token_expires_at:
37+
result["token_expires_at"] = self.token_expires_at.isoformat()
38+
39+
return result
40+
41+
@classmethod
42+
def from_dict(cls, data: dict) -> "UserCredentials":
43+
"""Create from dictionary loaded from JSON."""
44+
45+
token_expires_at = None
46+
if "token_expires_at" in data:
47+
token_expires_at = datetime.fromisoformat(data["token_expires_at"])
48+
49+
return cls(
50+
api_key=data["api_key"],
51+
token_expires_at=token_expires_at,
52+
username=data.get("username"),
53+
email=data.get("email"),
54+
)
55+
56+
def to_json(self) -> str:
57+
"""Convert to JSON string."""
58+
return json.dumps(self.to_dict(), indent=2)
59+
60+
@classmethod
61+
def from_json(cls, json_str: str) -> "UserCredentials":
62+
"""Create from JSON string."""
63+
data = json.loads(json_str)
64+
return cls.from_dict(data)

src/mcp_agent/cli/cloud/commands/auth/login/main.py

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -4,15 +4,15 @@
44
import typer
55
from rich.prompt import Confirm, Prompt
66

7-
from mcp_agent_cloud.auth import (
7+
from mcp_agent.cli.auth import (
88
UserCredentials,
99
load_credentials,
1010
save_credentials,
1111
)
12-
from mcp_agent_cloud.config import settings
13-
from mcp_agent_cloud.core.api_client import APIClient
14-
from mcp_agent_cloud.exceptions import CLIError
15-
from mcp_agent_cloud.ux import (
12+
from mcp_agent.cli.config import settings
13+
from mcp_agent.cli.core.api_client import APIClient
14+
from mcp_agent.cli.exceptions import CLIError
15+
from mcp_agent.cli.utils.ux import (
1616
print_info,
1717
print_success,
1818
print_warning,

src/mcp_agent/cli/cloud/commands/auth/logout/main.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,8 +3,8 @@
33
import typer
44
from rich.prompt import Confirm
55

6-
from mcp_agent_cloud.auth import clear_credentials, load_credentials
7-
from mcp_agent_cloud.ux import print_info, print_success
6+
from mcp_agent.cli.auth import clear_credentials, load_credentials
7+
from mcp_agent.cli.utils.ux import print_info, print_success
88

99

1010
def logout() -> None:

src/mcp_agent/cli/cloud/commands/auth/whoami/main.py

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -7,9 +7,9 @@
77
from rich.panel import Panel
88
from rich.table import Table
99

10-
from mcp_agent_cloud.auth import load_credentials
11-
from mcp_agent_cloud.exceptions import CLIError
12-
from mcp_agent_cloud.ux import print_error, print_info
10+
from mcp_agent.cli.auth import load_credentials
11+
from mcp_agent.cli.exceptions import CLIError
12+
from mcp_agent.cli.utils.ux import print_error, print_info
1313

1414

1515
def whoami() -> None:

0 commit comments

Comments
 (0)