Skip to content

Commit bfde6eb

Browse files
mikipaletclaude
andcommitted
fix: rebrand MCP server Late -> Zernio, support ZERNIO_API_KEY env var
Critical bug fix: MCP server now reads ZERNIO_API_KEY (with LATE_API_KEY fallback) instead of only LATE_API_KEY. Also reads ZERNIO_BASE_URL with LATE_BASE_URL fallback. Full rebrand across all MCP files: - server.py: FastMCP name, instructions, docstring config example, env var priority (ZERNIO_API_KEY > LATE_API_KEY), error messages - constants.py: SERVICE_NAME - routes.py: error messages, health service name, auth instructions - auth.py: docstrings - config.py: docstrings - http_server.py: startup messages, CLI description Function names (set_late_api_key, extract_late_api_key, etc.) kept for backwards compatibility with existing imports. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
1 parent b274fbc commit bfde6eb

6 files changed

Lines changed: 56 additions & 49 deletions

File tree

‎src/late/mcp/auth.py‎

Lines changed: 9 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,16 @@
1-
"""Authentication module for Late MCP HTTP server."""
1+
"""Authentication module for Zernio MCP HTTP server."""
22

33
import httpx
44
from starlette.requests import Request
55

66

77
def extract_late_api_key(request: Request) -> str | None:
88
"""
9-
Extract Late API key from request Authorization header.
9+
Extract Zernio API key from request Authorization header.
1010
11-
Expects: Authorization: Bearer <your_late_api_key>
11+
Expects: Authorization: Bearer <your_api_key>
12+
13+
Function name kept as extract_late_api_key for backwards compatibility.
1214
1315
Args:
1416
request: The incoming Starlette request.
@@ -24,10 +26,12 @@ def extract_late_api_key(request: Request) -> str | None:
2426

2527
async def verify_late_api_key(api_key: str) -> bool:
2628
"""
27-
Verify Late API key by making a test request to Late API.
29+
Verify Zernio API key by making a test request to Zernio API.
30+
31+
Function name kept as verify_late_api_key for backwards compatibility.
2832
2933
Args:
30-
api_key: The Late API key to verify.
34+
api_key: The Zernio API key to verify.
3135
3236
Returns:
3337
True if API key is valid, False otherwise.

‎src/late/mcp/config.py‎

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
"""Configuration management for Late MCP HTTP server."""
1+
"""Configuration management for Zernio MCP HTTP server."""
22

33
import os
44
from dataclasses import dataclass
@@ -44,7 +44,7 @@ def validate_environment() -> None:
4444
Validate required environment variables are set.
4545
4646
Note: No environment variables are required for the server.
47-
Users provide their Late API keys via request headers.
47+
Users provide their Zernio API keys via request headers.
4848
"""
4949
# No validation needed - users provide API keys in headers
5050
pass

‎src/late/mcp/constants.py‎

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
1-
"""Constants for Late MCP HTTP server."""
1+
"""Constants for Zernio MCP HTTP server."""
22

33
# Server information
4-
SERVICE_NAME = "Late MCP Server"
4+
SERVICE_NAME = "Zernio MCP Server"
55
SERVICE_VERSION = "1.1.2"
66
TRANSPORT_TYPE = "sse"
77

‎src/late/mcp/http_server.py‎

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
"""HTTP/SSE server for Late MCP."""
1+
"""HTTP/SSE server for Zernio MCP."""
22

33
import argparse
44
import sys
@@ -45,7 +45,7 @@ def create_app(mcp_server, debug: bool = False) -> Starlette:
4545

4646
def parse_args() -> argparse.Namespace:
4747
"""Parse command-line arguments."""
48-
parser = argparse.ArgumentParser(description="Late MCP HTTP/SSE Server")
48+
parser = argparse.ArgumentParser(description="Zernio MCP HTTP/SSE Server")
4949
parser.add_argument("--host", help="Host to bind to (default: 0.0.0.0)")
5050
parser.add_argument("--port", type=int, help="Port to listen on (default: 8080)")
5151
parser.add_argument("--debug", action="store_true", help="Enable debug mode")
@@ -54,14 +54,14 @@ def parse_args() -> argparse.Namespace:
5454

5555
def print_startup_info(config: ServerConfig) -> None:
5656
"""Print server startup information."""
57-
print("🚀 Late MCP HTTP Server starting...")
57+
print("Zernio MCP HTTP Server starting...")
5858
print(f" Host: {config.host}")
5959
print(f" Port: {config.port}")
6060
print(f" SSE endpoint: http://{config.host}:{config.port}{ENDPOINT_SSE}")
6161
print(f" Health check: http://{config.host}:{config.port}{ENDPOINT_HEALTH}")
6262
print(f" Debug mode: {'enabled' if config.debug else 'disabled'}")
6363
print()
64-
print("📡 Ready to accept MCP connections!")
64+
print("Ready to accept MCP connections!")
6565

6666

6767
def main() -> None:
@@ -81,7 +81,7 @@ def main() -> None:
8181

8282
mcp_server = mcp._mcp_server
8383
except (ImportError, AttributeError) as e:
84-
print(f"❌ Failed to access MCP server: {e}", file=sys.stderr)
84+
print(f"Failed to access MCP server: {e}", file=sys.stderr)
8585
sys.exit(1)
8686

8787
# Create app

‎src/late/mcp/routes.py‎

Lines changed: 13 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
"""Route handlers for Late MCP HTTP server."""
1+
"""Route handlers for Zernio MCP HTTP server."""
22

33
import sys
44

@@ -31,7 +31,7 @@ async def handle_root(_request: Request) -> JSONResponse:
3131
"health": f"{ENDPOINT_HEALTH} (GET) - Health check",
3232
},
3333
"documentation": DOCS_URL,
34-
"authentication": "Required: 'Authorization: Bearer YOUR_LATE_API_KEY'",
34+
"authentication": "Required: 'Authorization: Bearer YOUR_API_KEY'",
3535
}
3636
)
3737

@@ -41,7 +41,7 @@ async def handle_health(_request: Request) -> JSONResponse:
4141
return JSONResponse(
4242
{
4343
"status": "healthy",
44-
"service": "late-mcp-http",
44+
"service": "zernio-mcp-http",
4545
"version": SERVICE_VERSION,
4646
"transport": TRANSPORT_TYPE,
4747
}
@@ -63,30 +63,30 @@ def create_sse_handler(mcp_server, sse_transport: SseServerTransport, debug: boo
6363

6464
async def handle_sse(request: Request) -> Response:
6565
"""Handle SSE connection with authentication."""
66-
# Extract Late API key from request
67-
late_api_key = extract_late_api_key(request)
68-
if not late_api_key:
66+
# Extract API key from request
67+
api_key = extract_late_api_key(request)
68+
if not api_key:
6969
return JSONResponse(
70-
{"error": "Missing Late API key. Provide via Authorization header: 'Authorization: Bearer YOUR_API_KEY'"},
70+
{"error": "Missing API key. Provide via Authorization header: 'Authorization: Bearer YOUR_API_KEY'"},
7171
status_code=401
7272
)
7373

74-
# Verify Late API key by making test request
75-
if not await verify_late_api_key(late_api_key):
74+
# Verify API key by making test request
75+
if not await verify_late_api_key(api_key):
7676
return JSONResponse(
77-
{"error": "Invalid Late API key"},
77+
{"error": "Invalid API key"},
7878
status_code=401
7979
)
8080

8181
# Store API key in request state for use in MCP tools
82-
request.state.late_api_key = late_api_key
82+
request.state.late_api_key = api_key
8383

8484
# Establish SSE connection
8585
try:
8686
# Import here to set context variable before running MCP
8787
from late.mcp.server import set_late_api_key
8888

89-
set_late_api_key(late_api_key)
89+
set_late_api_key(api_key)
9090

9191
async with sse_transport.connect_sse(
9292
request.scope,
@@ -100,7 +100,7 @@ async def handle_sse(request: Request) -> Response:
100100
)
101101
except Exception as e:
102102
if debug:
103-
print(f"❌ SSE connection error: {e}", file=sys.stderr)
103+
print(f"SSE connection error: {e}", file=sys.stderr)
104104
return JSONResponse(
105105
{"error": "SSE connection failed"}, status_code=500
106106
)

‎src/late/mcp/server.py‎

Lines changed: 25 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
"""
2-
Late MCP Server.
2+
Zernio MCP Server.
33
4-
Exposes Late API functionality through Model Context Protocol.
4+
Exposes Zernio API functionality through Model Context Protocol.
55
66
Usage:
77
# Run directly
@@ -10,11 +10,11 @@
1010
# Or in Claude Desktop config:
1111
{
1212
"mcpServers": {
13-
"late": {
13+
"zernio": {
1414
"command": "uvx",
15-
"args": ["--from", "late-sdk[mcp]", "late-mcp"],
15+
"args": ["--from", "zernio-sdk[mcp]", "zernio-mcp"],
1616
"env": {
17-
"LATE_API_KEY": "your_api_key"
17+
"ZERNIO_API_KEY": "your_api_key"
1818
}
1919
}
2020
}
@@ -36,8 +36,8 @@
3636

3737
from .tool_definitions import use_tool_def
3838

39-
# Context variable to store the Late API key for the current connection
40-
_late_api_key: ContextVar[str | None] = ContextVar("late_api_key", default=None)
39+
# Context variable to store the Zernio API key for the current connection
40+
_zernio_api_key: ContextVar[str | None] = ContextVar("zernio_api_key", default=None)
4141

4242
# Cache for documentation content
4343
_docs_cache: dict[str, tuple[str, datetime]] = {}
@@ -46,36 +46,39 @@
4646

4747
# Initialize MCP server
4848
mcp = FastMCP(
49-
"Late",
49+
"Zernio",
5050
instructions="""
51-
Late API server for scheduling social media posts.
51+
Zernio API server for scheduling social media posts.
5252
5353
Available tools are prefixed by resource:
5454
- accounts_* : Manage connected social media accounts
5555
- profiles_* : Manage profiles (groups of accounts)
5656
- posts_* : Create, list, update, delete posts
5757
- media_* : Upload images and videos
58-
- docs_* : Search Late API documentation
58+
- docs_* : Search Zernio API documentation
5959
""",
6060
)
6161

6262

6363
def set_late_api_key(api_key: str) -> None:
6464
"""
65-
Set the Late API key for the current async context.
65+
Set the Zernio API key for the current async context.
66+
67+
Kept as set_late_api_key for backwards compatibility with HTTP server routes.
6668
6769
Args:
68-
api_key: The Late API key to use for this connection.
70+
api_key: The Zernio API key to use for this connection.
6971
"""
70-
_late_api_key.set(api_key)
72+
_zernio_api_key.set(api_key)
7173

7274

7375
def _get_client() -> Late:
7476
"""
75-
Get Late client with API key from context or environment.
77+
Get Zernio client with API key from context or environment.
7678
7779
For HTTP/SSE connections, uses the API key from the current context.
78-
For STDIO connections (Claude Desktop), falls back to LATE_API_KEY env var.
80+
For STDIO connections (Claude Desktop), falls back to env vars.
81+
Priority: ZERNIO_API_KEY > LATE_API_KEY (legacy).
7982
8083
Returns:
8184
Late client instance.
@@ -84,20 +87,20 @@ def _get_client() -> Late:
8487
ValueError: If no API key is available.
8588
"""
8689
# Try to get API key from context (HTTP/SSE mode)
87-
api_key = _late_api_key.get()
90+
api_key = _zernio_api_key.get()
8891

89-
# Fall back to environment variable (STDIO mode for Claude Desktop)
92+
# Fall back to environment variables (STDIO mode for Claude Desktop)
9093
if not api_key:
91-
api_key = os.getenv("LATE_API_KEY", "")
94+
api_key = os.getenv("ZERNIO_API_KEY") or os.getenv("LATE_API_KEY", "")
9295

9396
if not api_key:
9497
raise ValueError(
95-
"Late API key is required. "
96-
"For HTTP/SSE: provide via X-Late-API-Key header. "
97-
"For STDIO: set LATE_API_KEY environment variable."
98+
"Zernio API key is required. "
99+
"For HTTP/SSE: provide via Authorization: Bearer header. "
100+
"For STDIO: set ZERNIO_API_KEY environment variable."
98101
)
99102

100-
base_url = os.getenv("LATE_BASE_URL", None)
103+
base_url = os.getenv("ZERNIO_BASE_URL") or os.getenv("LATE_BASE_URL", None)
101104
return Late(api_key=api_key, base_url=base_url)
102105

103106

0 commit comments

Comments
 (0)