feat: rework auth model with UserToken and Daedalus/Pallas integration
- Rename MCPToken to UserToken across models, views, and tests - Update URL names from mcp-token-* to token-* - Add Daedalus/Pallas integration design doc (v2) - Switch docker-compose to build local mnemosyne:local image via shared build config instead of pulling from git.helu.ca
This commit is contained in:
@@ -0,0 +1,77 @@
|
||||
"""Create an MCP bearer token for a user. Token is printed once and not retrievable later."""
|
||||
|
||||
from datetime import timedelta
|
||||
|
||||
from django.contrib.auth import get_user_model
|
||||
from django.core.management.base import BaseCommand, CommandError
|
||||
from django.utils import timezone
|
||||
|
||||
from mcp_server.models import UserToken
|
||||
|
||||
|
||||
class Command(BaseCommand):
|
||||
help = "Create an API token for a user and print the full token (shown once)."
|
||||
|
||||
def add_arguments(self, parser):
|
||||
parser.add_argument(
|
||||
"--user",
|
||||
required=True,
|
||||
help="Username or email of the owner.",
|
||||
)
|
||||
parser.add_argument(
|
||||
"--name",
|
||||
required=True,
|
||||
help="Friendly token name (e.g. 'Claude Desktop').",
|
||||
)
|
||||
parser.add_argument(
|
||||
"--tools",
|
||||
default="",
|
||||
help="Comma-separated tool whitelist. Empty = all tools allowed.",
|
||||
)
|
||||
parser.add_argument(
|
||||
"--expires-days",
|
||||
type=int,
|
||||
default=None,
|
||||
help="Days until expiry. Omit for no expiry.",
|
||||
)
|
||||
|
||||
def handle(self, *args, **options):
|
||||
User = get_user_model()
|
||||
identifier = options["user"]
|
||||
try:
|
||||
user = User.objects.get(email=identifier)
|
||||
except User.DoesNotExist:
|
||||
try:
|
||||
user = User.objects.get(username=identifier)
|
||||
except User.DoesNotExist:
|
||||
raise CommandError(f'User "{identifier}" not found.')
|
||||
|
||||
if not user.is_active:
|
||||
raise CommandError(f'User "{identifier}" is inactive.')
|
||||
|
||||
allowed_tools = [t.strip() for t in options["tools"].split(",") if t.strip()]
|
||||
|
||||
expires_at = None
|
||||
if options["expires_days"] is not None:
|
||||
if options["expires_days"] < 1:
|
||||
raise CommandError("--expires-days must be at least 1.")
|
||||
expires_at = timezone.now() + timedelta(days=options["expires_days"])
|
||||
|
||||
token, plaintext = UserToken.objects.create_token(
|
||||
user=user,
|
||||
name=options["name"],
|
||||
allowed_tools=allowed_tools,
|
||||
expires_at=expires_at,
|
||||
)
|
||||
|
||||
self.stdout.write(self.style.SUCCESS("API token created"))
|
||||
self.stdout.write(f" Name: {token.name}")
|
||||
self.stdout.write(f" User: {user}")
|
||||
if allowed_tools:
|
||||
self.stdout.write(f" Tools: {', '.join(allowed_tools)}")
|
||||
else:
|
||||
self.stdout.write(" Tools: (all)")
|
||||
if expires_at:
|
||||
self.stdout.write(f" Expires: {expires_at.isoformat()}")
|
||||
self.stdout.write(self.style.WARNING(" Token (shown once — store it now):"))
|
||||
self.stdout.write(f" {plaintext}")
|
||||
Reference in New Issue
Block a user