Skip to main content
Glama

Discourse MCP

Official
by discourse
state.ts2.5 kB
import type { Logger } from "../util/logger.js"; import { HttpClient, type AuthMode } from "../http/client.js"; export type AuthOverride = { site: string; // base URL or origin to match api_key?: string; api_username?: string; }; function normalizeBase(url: string): string { const u = new URL(url); u.pathname = "/"; u.search = ""; u.hash = ""; return u.toString().replace(/\/$/, ""); } export class SiteState { private currentSiteBase?: string; private currentClient?: HttpClient; private readonly clientCache = new Map<string, HttpClient>(); constructor( private opts: { logger: Logger; timeoutMs: number; defaultAuth: AuthMode; authOverrides?: AuthOverride[]; } ) {} getSiteBase(): string | undefined { return this.currentSiteBase; } ensureSelectedSite(): { base: string; client: HttpClient } { if (!this.currentSiteBase || !this.currentClient) { throw new Error("No site selected. Call discourse_select_site first."); } return { base: this.currentSiteBase, client: this.currentClient }; } buildClientForSite(siteUrl: string): { base: string; client: HttpClient } { const base = normalizeBase(siteUrl); const cached = this.clientCache.get(base); if (cached) return { base, client: cached }; const auth = this.resolveAuthForSite(base); const client = new HttpClient({ baseUrl: base, timeoutMs: this.opts.timeoutMs, logger: this.opts.logger, auth, } as any); this.clientCache.set(base, client); return { base, client }; } selectSite(siteUrl: string): { base: string; client: HttpClient } { const { base, client } = this.buildClientForSite(siteUrl); this.currentSiteBase = base; this.currentClient = client; return { base, client }; } private resolveAuthForSite(base: string): AuthMode { const overrides = this.opts.authOverrides || []; const match = overrides.find((o) => normalizeBase(o.site) === base || this.sameOrigin(o.site, base)); if (match) { if (match.api_key) return { type: "api_key", key: match.api_key, username: match.api_username }; } return this.opts.defaultAuth; } private sameOrigin(a: string, b: string): boolean { try { const ua = new URL(a); const ub = new URL(b); return ua.protocol === ub.protocol && ua.host === ub.host; } catch { return false; } } } export type SiteStateInit = ConstructorParameters<typeof SiteState>[0];

MCP directory API

We provide all the information about MCP servers via our MCP API.

curl -X GET 'https://glama.ai/api/mcp/v1/servers/discourse/discourse-mcp'

If you have feedback or need assistance with the MCP directory API, please join our Discord server