API Endpoints
Seed exposes multiple HTTP endpoints for MCP protocol handling, OAuth 2.1 authentication, and operational monitoring.
Endpoint Overview
Public Endpoints (No Authentication)
| Method | Path | Purpose |
|---|---|---|
| GET | /health | Health check and version info |
| GET | /.well-known/oauth-protected-resource | OAuth Protected Resource metadata (RFC 9728) |
| GET | /.well-known/oauth-authorization-server | OAuth Authorization Server metadata (RFC 8414) |
| GET | /oauth/authorize | OAuth authorization endpoint (proxy) |
| POST | /oauth/token | OAuth token exchange endpoint (proxy) |
| POST | /oauth/register | Dynamic Client Registration (RFC 7591) |
| GET | /metrics | Prometheus metrics (if METRICS_ENABLED=true) |
| GET | / | Documentation homepage |
| GET | /assets/** | Documentation static assets |
Protected Endpoints (JWT Required)
| Method | Path | Purpose |
|---|---|---|
| POST | /mcp | MCP JSON-RPC endpoint |
| DELETE | /mcp | Terminate MCP session |
Rate Limited Endpoints
| Endpoint | Per-IP Limit | Global Limit | Window |
|---|---|---|---|
POST /mcp | 100 req | 10,000 req | 1 minute |
DELETE /mcp | 100 req | 10,000 req | 1 minute |
POST /oauth/register | 10 reg | 1,000 reg | 1 hour |
Health Check
Health check endpoint for load balancers and monitoring.
Endpoint: GET /health
Authentication: None
Request: No parameters
Response: 200 OK
{
"status": "ok",
"version": "0.1.3"
}Response Fields:
status(string): Always"ok"if server is runningversion(string): Server version frompackage.json
Use Cases:
- Kubernetes/Docker liveness probes
- Load balancer health checks
- Monitoring and alerting
Example:
curl http://localhost:3000/healthMCP JSON-RPC Endpoint
Main endpoint for MCP protocol communication.
Endpoint: POST /mcp
Authentication: Required (JWT Bearer token)
Rate Limiting: 100 requests/minute per IP
Content-Type: application/json
Headers:
Authorization: Bearer <jwt_token>
mcp-session-id: <session_id> # Optional for existing sessionsRequest Body (JSON-RPC 2.0):
{
"jsonrpc": "2.0",
"method": "initialize",
"params": {
"protocolVersion": "2024-11-05",
"capabilities": {},
"clientInfo": {
"name": "example-client",
"version": "1.0.0"
}
},
"id": 1
}Initialize Request
Creates a new MCP session and returns session ID.
Method: initialize
Required Parameters:
protocolVersion(string): MCP protocol version (e.g.,"2024-11-05")capabilities(object): Client capabilitiesclientInfo(object): Client name and version
Response: 200 OK
{
"jsonrpc": "2.0",
"result": {
"protocolVersion": "2024-11-05",
"capabilities": {
"tools": {},
"prompts": {},
"resources": {}
},
"serverInfo": {
"name": "seed",
"version": "0.1.3"
}
},
"id": 1
}Response Headers:
mcp-session-id: 550e8400-e29b-41d4-a716-446655440000Session Behavior:
- Session ID must be included in all subsequent requests
- Session expires after 24 hours of inactivity (configurable via
MCP_SESSION_TTL_SECONDS) - Session TTL refreshes on each request (sliding window)
Tools List Request
List available MCP tools.
Method: tools/list
Headers:
mcp-session-id: 550e8400-e29b-41d4-a716-446655440000Request:
{
"jsonrpc": "2.0",
"method": "tools/list",
"id": 2
}Response: 200 OK
{
"jsonrpc": "2.0",
"result": {
"tools": [
{
"name": "echo-message",
"description": "Echo back a message",
"inputSchema": {
"type": "object",
"properties": {
"message": {
"type": "string",
"description": "Message to echo"
}
},
"required": ["message"]
}
},
{
"name": "random-number",
"description": "Generate a random number",
"inputSchema": {
"type": "object",
"properties": {
"min": { "type": "number" },
"max": { "type": "number" }
}
}
}
]
},
"id": 2
}Tool Call Request
Invoke an MCP tool.
Method: tools/call
Request:
{
"jsonrpc": "2.0",
"method": "tools/call",
"params": {
"name": "random-number",
"arguments": {
"min": 1,
"max": 100
}
},
"id": 3
}Response: 200 OK
{
"jsonrpc": "2.0",
"result": {
"content": [
{
"type": "text",
"text": "42"
}
]
},
"id": 3
}Prompts List Request
List available MCP prompts.
Method: prompts/list
Request:
{
"jsonrpc": "2.0",
"method": "prompts/list",
"id": 4
}Response: 200 OK
{
"jsonrpc": "2.0",
"result": {
"prompts": [
{
"name": "greeting",
"description": "Generate a friendly greeting message",
"arguments": [
{
"name": "name",
"description": "Name of the person to greet",
"required": true
},
{
"name": "style",
"description": "Greeting style (formal, casual, enthusiastic)",
"required": false
}
]
}
]
},
"id": 4
}Prompt Get Request
Get a prompt with arguments.
Method: prompts/get
Request:
{
"jsonrpc": "2.0",
"method": "prompts/get",
"params": {
"name": "greeting",
"arguments": {
"name": "Alice",
"style": "enthusiastic"
}
},
"id": 5
}Response: 200 OK
{
"jsonrpc": "2.0",
"result": {
"description": "Generate a friendly greeting message",
"messages": [
{
"role": "user",
"content": {
"type": "text",
"text": "Generate an enthusiastic greeting for Alice"
}
}
]
},
"id": 5
}Resources List Request
List available MCP resources.
Method: resources/list
Request:
{
"jsonrpc": "2.0",
"method": "resources/list",
"id": 6
}Response: 200 OK
{
"jsonrpc": "2.0",
"result": {
"resources": [
{
"uri": "config://server",
"name": "Server Configuration",
"description": "Current server configuration and environment",
"mimeType": "application/json"
}
]
},
"id": 6
}Resource Read Request
Read an MCP resource.
Method: resources/read
Request:
{
"jsonrpc": "2.0",
"method": "resources/read",
"params": {
"uri": "config://server"
},
"id": 7
}Response: 200 OK
{
"jsonrpc": "2.0",
"result": {
"contents": [
{
"uri": "config://server",
"mimeType": "application/json",
"text": "{\"name\":\"seed\",\"version\":\"0.1.3\",\"environment\":\"production\"}"
}
]
},
"id": 7
}Error Responses
Invalid Session (session not found or expired):
HTTP/1.1 404 Not Found
Content-Type: application/json
{
"jsonrpc": "2.0",
"error": {
"code": -32000,
"message": "Invalid or expired session",
"data": {
"reason": "session_not_found"
}
},
"id": null
}Rate Limit Exceeded:
HTTP/1.1 429 Too Many Requests
X-RateLimit-Limit: 100
X-RateLimit-Remaining: 0
X-RateLimit-Reset: 1704643200
Retry-After: 45
{
"jsonrpc": "2.0",
"error": {
"code": -32000,
"message": "Too Many Requests",
"data": {
"reason": "rate_limit_exceeded",
"retryAfter": 45
}
},
"id": null
}Unauthorized (missing or invalid JWT):
HTTP/1.1 401 Unauthorized
WWW-Authenticate: Bearer resource_metadata="https://your-server.com/.well-known/oauth-protected-resource"
{
"jsonrpc": "2.0",
"error": {
"code": -32001,
"message": "Unauthorized",
"data": {
"reason": "invalid_token",
"details": "JWT signature verification failed"
}
},
"id": null
}MCP Session Termination
Explicitly terminate an MCP session.
Endpoint: DELETE /mcp
Authentication: Required (JWT Bearer token)
Rate Limiting: 100 requests/minute per IP
Headers:
Authorization: Bearer <jwt_token>
mcp-session-id: <session_id>Request: No body
Response: 200 OK
{
"jsonrpc": "2.0",
"result": {
"status": "terminated"
},
"id": null
}Response Behavior:
- Session removed from in-memory transport registry
- Session metadata deleted from Redis
- Subsequent requests with this session ID will return 404
Use Cases:
- Graceful client shutdown
- Explicit session cleanup
- Resource conservation
OAuth Authorization
Initiates OAuth 2.1 authorization flow with PKCE.
Endpoint: GET /oauth/authorize
Authentication: None (public endpoint)
Query Parameters:
client_id=<client_id>
redirect_uri=<redirect_uri>
response_type=code
scope=openid+profile+email
state=<state_value>
code_challenge=<code_challenge>
code_challenge_method=S256Parameter Details:
client_id(required): OAuth client ID (static or registered via DCR)redirect_uri(required): Callback URL (must be registered for DCR clients)response_type(required): Must be"code"(authorization code flow)scope(optional): Requested scopes (e.g.,openid profile email)state(required): CSRF protection tokencode_challenge(required): PKCE code challenge (SHA256 hash of verifier)code_challenge_method(required): Must be"S256"
Behavior:
DCR Client Validation (for
client_idstarting withseed-):- Validates client exists in Redis
- Validates
redirect_urimatches registered URIs - Replaces dynamic
client_idwith static IdP client for upstream
Redirect to IdP:
- Proxies request to upstream authorization endpoint (
OAUTH_AUTHORIZATION_URL) - Preserves all query parameters
- Returns
302 Foundredirect
- Proxies request to upstream authorization endpoint (
Response: 302 Found
Location: https://idp.example.com/authorize?client_id=static-client&redirect_uri=...Error Responses:
Invalid Client:
HTTP/1.1 400 Bad Request
{
"error": "invalid_client",
"error_description": "Unknown or expired client_id"
}Invalid Redirect URI:
HTTP/1.1 400 Bad Request
{
"error": "invalid_redirect_uri",
"error_description": "redirect_uri does not match any registered URI"
}Example Authorization URL:
https://seed.example.com/oauth/authorize?
client_id=seed-abc123xyz&
redirect_uri=http://localhost:3000/callback&
response_type=code&
scope=openid+profile+email&
state=random-state-value&
code_challenge=base64url-encoded-sha256-hash&
code_challenge_method=S256OAuth Token Exchange
Exchanges authorization code for access token (with PKCE verification).
Endpoint: POST /oauth/token
Authentication: None (public endpoint, PKCE provides security)
Content-Type: application/x-www-form-urlencoded or application/json
Request Body (authorization_code grant):
grant_type=authorization_code
code=<authorization_code>
redirect_uri=<redirect_uri>
client_id=<client_id>
code_verifier=<code_verifier>Request Body (refresh_token grant):
grant_type=refresh_token
refresh_token=<refresh_token>
client_id=<client_id>Parameter Details:
authorization_code Grant:
grant_type(required): Must be"authorization_code"code(required): Authorization code from/oauth/authorizeredirect_uri(required): Same URI used in authorization requestclient_id(required): OAuth client IDcode_verifier(required): PKCE code verifier (plaintext)
refresh_token Grant:
grant_type(required): Must be"refresh_token"refresh_token(required): Refresh token from previous token responseclient_id(required): OAuth client ID
Behavior:
- Validate Grant Type: Must be
authorization_codeorrefresh_token - Validate Required Parameters: Check all required fields present
- DCR Client Validation (for
client_idstarting withseed-):- Validate client exists in Redis
- Validate
redirect_urimatches registered URIs (for auth code grant) - Replace dynamic
client_idwith static IdP client
- Proxy to IdP: Forward request to upstream token endpoint (
OAUTH_TOKEN_URL) - Return Response: Proxy status code and body from IdP
Response: 200 OK
{
"access_token": "eyJhbGciOiJSUzI1NiIs...",
"token_type": "Bearer",
"expires_in": 3600,
"refresh_token": "def502003c2...",
"scope": "openid profile email"
}Response Fields:
access_token(string): JWT access tokentoken_type(string): Always"Bearer"expires_in(number): Token lifetime in secondsrefresh_token(string, optional): Refresh token for getting new access tokensscope(string, optional): Granted scopes
Error Responses:
Invalid Request:
HTTP/1.1 400 Bad Request
{
"error": "invalid_request",
"error_description": "Missing required parameter: code"
}Invalid Grant:
HTTP/1.1 400 Bad Request
{
"error": "invalid_grant",
"error_description": "redirect_uri does not match registered URI"
}Invalid Client:
HTTP/1.1 401 Unauthorized
{
"error": "invalid_client",
"error_description": "Unknown or expired client_id"
}Unsupported Grant Type:
HTTP/1.1 400 Bad Request
{
"error": "unsupported_grant_type",
"error_description": "Unsupported grant type: implicit"
}Dynamic Client Registration
Register OAuth client dynamically per RFC 7591.
Endpoint: POST /oauth/register
Authentication: None (public endpoint)
Rate Limiting: 10 registrations/hour per IP
Content-Type: application/json
Request Body:
{
"client_name": "My OAuth Client",
"redirect_uris": [
"https://app.example.com/callback",
"http://localhost:3000/callback"
],
"grant_types": ["authorization_code", "refresh_token"],
"response_types": ["code"],
"token_endpoint_auth_method": "none",
"software_id": "my-app",
"software_version": "1.0.0"
}Required Parameters:
redirect_uris(array): At least one redirect URI (max 10)
Optional Parameters:
client_name(string): Human-readable client namegrant_types(array): Grant types (default:["authorization_code"])response_types(array): Response types (default:["code"])token_endpoint_auth_method(string): Auth method (default:"none")software_id(string): Software identifiersoftware_version(string): Software version
Validation Rules:
Redirect URI:
- Must be valid URL
- Must use HTTPS (except
localhostand127.0.0.1) - Must not contain fragment (
#) - Maximum 10 URIs per client
Grant Types:
- Supported:
authorization_code,refresh_token
Response Types:
- Supported:
code
Auth Methods:
- Supported:
none,client_secret_post,client_secret_basic
Response: 201 Created
{
"client_id": "seed-abc123xyz789",
"client_name": "My OAuth Client",
"redirect_uris": [
"https://app.example.com/callback",
"http://localhost:3000/callback"
],
"grant_types": ["authorization_code", "refresh_token"],
"response_types": ["code"],
"token_endpoint_auth_method": "none",
"client_id_issued_at": 1704643200,
"client_secret_expires_at": 0,
"software_id": "my-app",
"software_version": "1.0.0"
}Response Fields:
client_id(string): Generated client ID (format:seed-<12chars>)client_id_issued_at(number): Unix timestamp of registrationclient_secret_expires_at(number): Always0(public clients don't expire)- All other fields echo the request
Client Storage:
- Stored in Redis with TTL (default: 30 days, configurable via
DCR_CLIENT_TTL) - Key format:
dcr:client:<client_id> - Automatic expiration handled by Redis
Error Responses:
Invalid Redirect URI:
HTTP/1.1 400 Bad Request
{
"error": "invalid_redirect_uri",
"error_description": "redirect_uri must use https"
}Invalid Client Metadata:
HTTP/1.1 400 Bad Request
{
"error": "invalid_client_metadata",
"error_description": "redirect_uris exceeds maximum of 10"
}OAuth Discovery Endpoints
Protected Resource Metadata
Endpoint: GET /.well-known/oauth-protected-resource
Authentication: None
Response: 200 OK
{
"resource": "https://seed.example.com",
"authorization_servers": [
"https://seed.example.com"
],
"scopes_supported": ["openid", "profile", "email"],
"bearer_methods_supported": ["header"],
"resource_documentation": "https://gitlab.byterecursion.com/mcp-servers/seed"
}Fields:
resource(string): Protected resource identifier (Seed's base URL)authorization_servers(array): Authorization servers (points to Seed as OAuth proxy)scopes_supported(array): Supported OAuth scopesbearer_methods_supported(array): Token transmission methodsresource_documentation(string): Documentation URL
RFC: RFC 9728 - OAuth 2.0 Protected Resource Metadata
Authorization Server Metadata
Endpoint: GET /.well-known/oauth-authorization-server
Authentication: None
Caching: 5-minute in-memory cache
Response: 200 OK
{
"issuer": "https://idp.example.com/application/o/my-app/",
"authorization_endpoint": "https://seed.example.com/oauth/authorize",
"token_endpoint": "https://seed.example.com/oauth/token",
"registration_endpoint": "https://seed.example.com/oauth/register",
"jwks_uri": "https://idp.example.com/application/o/my-app/jwks/",
"scopes_supported": ["openid", "profile", "email"],
"response_types_supported": ["code"],
"grant_types_supported": ["authorization_code", "refresh_token"],
"token_endpoint_auth_methods_supported": ["none"],
"code_challenge_methods_supported": ["S256"]
}Fields:
issuer(string): OAuth issuer (upstream IdP)authorization_endpoint(string): Seed's authorization proxytoken_endpoint(string): Seed's token proxyregistration_endpoint(string): Seed's DCR endpointjwks_uri(string): Public key endpoint (upstream IdP)scopes_supported(array): Supported scopesresponse_types_supported(array): Supported response typesgrant_types_supported(array): Supported grant typestoken_endpoint_auth_methods_supported(array): Auth methodscode_challenge_methods_supported(array): PKCE methods
Design Choice: Returns Seed's proxy endpoints (not direct IdP endpoints) to maintain control over OAuth flow.
RFC: RFC 8414 - OAuth 2.0 Authorization Server Metadata
Prometheus Metrics
Metrics endpoint for monitoring and alerting.
Endpoint: GET /metrics
Authentication: None (public if enabled)
Configuration: METRICS_ENABLED=true
Content-Type: application/openmetrics-text; version=1.0.0; charset=utf-8
Response: 200 OK
# HELP http_request_duration_seconds Duration of HTTP requests in seconds
# TYPE http_request_duration_seconds histogram
http_request_duration_seconds_bucket{method="POST",route="/mcp",status_code="200",le="0.01"} 45
http_request_duration_seconds_bucket{method="POST",route="/mcp",status_code="200",le="0.05"} 89
http_request_duration_seconds_sum{method="POST",route="/mcp",status_code="200"} 12.5
http_request_duration_seconds_count{method="POST",route="/mcp",status_code="200"} 100
# HELP mcp_sessions_active Number of active MCP sessions
# TYPE mcp_sessions_active gauge
mcp_sessions_active 42Security Note: This endpoint is public when enabled. Recommended to use network-level access control (firewall rules, VPC restrictions).
Metrics Categories:
- HTTP metrics (request duration, total requests)
- MCP metrics (sessions, tool invocations)
- Authentication metrics (attempts, token validation)
- JWKS metrics (cache hits, refreshes)
- Redis metrics (operations, latency)
- Rate limiting metrics (violations, usage)
See Also: Observability for complete metrics reference.
Documentation Endpoints
Static documentation served by VitePress.
Endpoints:
GET /- Documentation homepageGET /assets/**- Static assets (CSS, JS, images)GET /mcp-server/**- MCP server documentationGET /tools/**- Tools documentationGET /prompts/**- Prompts documentationGET /404.html- VitePress 404 pageGET /hashmap.json- VitePress route map
Authentication: None (public)
Content-Type: text/html, text/css, application/javascript, etc.
Implementation: See docs.ts
Common Response Headers
Rate Limiting Headers
Included in all responses to rate-limited endpoints:
X-RateLimit-Limit: 100
X-RateLimit-Remaining: 73
X-RateLimit-Reset: 1704643200Fields:
X-RateLimit-Limit: Maximum requests allowed in windowX-RateLimit-Remaining: Requests remaining in current windowX-RateLimit-Reset: Unix timestamp when limit resets
When rate limit is exceeded:
Retry-After: 45CORS Headers
For cross-origin requests:
Access-Control-Allow-Origin: https://claude.ai
Access-Control-Allow-Credentials: true
Access-Control-Allow-Methods: GET, POST, PUT, DELETE, OPTIONS
Access-Control-Allow-Headers: Content-Type, Authorization, mcp-session-id
Access-Control-Expose-Headers: X-RateLimit-Limit, X-RateLimit-Remaining, X-RateLimit-Reset
Access-Control-Max-Age: 86400Security Headers
Applied to all responses (via Helmet):
X-Content-Type-Options: nosniff
X-Frame-Options: DENY
X-DNS-Prefetch-Control: off
Referrer-Policy: strict-origin-when-cross-origin
Cross-Origin-Opener-Policy: same-origin
Cross-Origin-Resource-Policy: cross-originProduction-only (HTTPS):
Strict-Transport-Security: max-age=31536000; includeSubDomains; preloadError Response Format
All errors use JSON-RPC 2.0 format for consistency.
Standard Error Structure:
{
"jsonrpc": "2.0",
"error": {
"code": -32001,
"message": "Unauthorized",
"data": {
"reason": "invalid_token",
"details": "JWT signature verification failed"
}
},
"id": null
}Error Codes:
-32001: Authentication error (401)-32000: Server error (429, 403, 404, 500, etc.)
OAuth Error Format:
{
"error": "invalid_client",
"error_description": "Unknown or expired client_id"
}See Also: Error Handling (planned) for comprehensive error documentation.
Configuration Reference
Environment Variables
# Server
BASE_URL=https://seed.example.com
PORT=3000
# Authentication
AUTH_REQUIRED=true
OIDC_ISSUER=https://idp.example.com/application/o/my-app/
OIDC_AUDIENCE=my-client-id
OIDC_JWKS_URL=https://idp.example.com/application/o/my-app/jwks/
# OAuth
OAUTH_AUTHORIZATION_URL=https://idp.example.com/application/o/authorize/
OAUTH_TOKEN_URL=https://idp.example.com/application/o/token/
# DCR
DCR_CLIENT_TTL=2592000 # 30 days
DCR_RATE_LIMIT_WINDOW_MS=3600000 # 1 hour
DCR_RATE_LIMIT_MAX=10 # 10 registrations per IP per hour
# MCP
MCP_SESSION_TTL_SECONDS=86400 # 24 hours
MCP_RATE_LIMIT_WINDOW_MS=60000 # 1 minute
MCP_RATE_LIMIT_MAX=100 # 100 requests per IP per minute
# Rate Limiting
RATE_LIMIT_ENABLED=true
# Metrics
METRICS_ENABLED=true
# Redis
REDIS_URL=redis://redis:6379Implementation Files
- MCP Routes:
src/routes/mcp.ts- MCP JSON-RPC and session management - OAuth Routes:
src/routes/oauth-authorize.ts- Authorization endpointsrc/routes/oauth-token.ts- Token exchange endpointsrc/routes/oauth-register.ts- Dynamic client registrationsrc/routes/oauth-protected-resource.ts- Protected resource metadatasrc/routes/oauth-authorization-server.ts- Authorization server metadata
- Operational Routes:
src/routes/health.ts- Health checksrc/routes/metrics.ts- Prometheus metricssrc/routes/docs.ts- Documentation serving
- Router:
src/routes/index.ts- Route registration
Related Documentation
- MCP Server Design - MCP protocol implementation
- OAuth 2.1 Implementation - OAuth flow details
- Authentication Flow - JWT validation
- Rate Limiting - Rate limiting details
- Middleware Architecture - Request processing pipeline
- Observability - Metrics and logging