/** * Static configuration for the MCP server. * * The origin is read from NEXTAUTH_URL rather than derived from the incoming * request. `publicOrigin()` in src/lib/origin.ts explains why for links; here it * matters more. RFC 9728 requires the `resource` field of the protected resource * metadata to match the URL the user typed into their client byte for byte, and * RFC 8414 requires the OAuth `issuer` to equal the origin it was discovered at. * Deriving either from X-Forwarded-* means a proxy misconfiguration shows up as a * silent connector failure with no useful error, so it is pinned to config instead. */ export const MCP_SERVER_NAME = "drinktracker" export const MCP_SERVER_VERSION = "1.0.0" /** Path the MCP endpoint is mounted at. Clients are given the full URL. */ export const MCP_PATH = "/api/mcp" /** * Scopes. Two axes, read and write, over two halves of the data: * * drinks:* the collection and journal - drinks, ratings, wishlist, preferences * bar:* the inventory and what can be made from it - bar items, recipes * * Kept deliberately coarse. A consent screen listing eight scopes is a consent * screen nobody reads. */ export const MCP_SCOPES = [ "drinks:read", "drinks:write", "bar:read", "bar:write", ] as const export type McpScope = (typeof MCP_SCOPES)[number] /** Everything a read-only connection gets. The default when minting a token. */ export const MCP_READ_SCOPES: McpScope[] = ["drinks:read", "bar:read"] /** Full access. */ export const MCP_ALL_SCOPES: McpScope[] = [...MCP_SCOPES] export function isMcpScope(value: string): value is McpScope { return (MCP_SCOPES as readonly string[]).includes(value) } /** Public origin, no trailing slash. */ export function mcpBaseUrl(): string { const configured = process.env.NEXTAUTH_URL if (configured) return configured.replace(/\/$/, "") // Only reachable in local development, where NEXTAUTH_URL is usually unset. return "http://localhost:3000" } /** * The resource identifier for this MCP server, which is also the URL a user * pastes into claude.ai. Must match their input exactly. */ export function mcpResourceUrl(): string { return `${mcpBaseUrl()}${MCP_PATH}` }