Skip to main content
Glama

docs-mcp-server

default.ts7.64 kB
/** * Default command - Starts unified server when no subcommand is specified. */ import type { Command } from "commander"; import { Option } from "commander"; import { startAppServer } from "../../app"; import { startStdioServer } from "../../mcp/startStdioServer"; import { initializeTools } from "../../mcp/tools"; import type { PipelineOptions } from "../../pipeline"; import { createLocalDocumentManagement } from "../../store"; import { analytics, TelemetryEvent } from "../../telemetry"; import { DEFAULT_HOST, DEFAULT_HTTP_PORT } from "../../utils/config"; import { LogLevel, logger, setLogLevel } from "../../utils/logger"; import { registerGlobalServices } from "../main"; import { createAppServerConfig, createPipelineWithCallbacks, ensurePlaywrightBrowsersInstalled, parseAuthConfig, resolveEmbeddingContext, resolveProtocol, validateAuthConfig, validateHost, validatePort, warnHttpUsage, } from "../utils"; export function createDefaultAction(program: Command): Command { return ( program .addOption( new Option("--protocol <protocol>", "Protocol for MCP server") .env("DOCS_MCP_PROTOCOL") .default("auto") .choices(["auto", "stdio", "http"]), ) .addOption( new Option("--port <number>", "Port for the server") .env("DOCS_MCP_PORT") .env("PORT") .default(DEFAULT_HTTP_PORT.toString()) .argParser((v: string) => { const n = Number(v); if (!Number.isInteger(n) || n < 1 || n > 65535) { throw new Error("Port must be an integer between 1 and 65535"); } return String(n); }), ) .addOption( new Option("--host <host>", "Host to bind the server to") .env("DOCS_MCP_HOST") .env("HOST") .default(DEFAULT_HOST) .argParser(validateHost), ) .addOption( new Option( "--embedding-model <model>", "Embedding model configuration (e.g., 'openai:text-embedding-3-small')", ).env("DOCS_MCP_EMBEDDING_MODEL"), ) .option("--resume", "Resume interrupted jobs on startup", false) .option("--no-resume", "Do not resume jobs on startup") .option( "--read-only", "Run in read-only mode (only expose read tools, disable write/job tools)", false, ) // Auth options .addOption( new Option( "--auth-enabled", "Enable OAuth2/OIDC authentication for MCP endpoints", ) .env("DOCS_MCP_AUTH_ENABLED") .argParser((value) => { if (value === undefined) { return ( process.env.DOCS_MCP_AUTH_ENABLED === "true" || process.env.DOCS_MCP_AUTH_ENABLED === "1" ); } return value; }) .default(false), ) .addOption( new Option( "--auth-issuer-url <url>", "Issuer/discovery URL for OAuth2/OIDC provider", ).env("DOCS_MCP_AUTH_ISSUER_URL"), ) .addOption( new Option( "--auth-audience <id>", "JWT audience claim (identifies this protected resource)", ).env("DOCS_MCP_AUTH_AUDIENCE"), ) .action( async (options: { protocol: string; port: string; host: string; embeddingModel?: string; resume: boolean; readOnly: boolean; authEnabled?: boolean; authIssuerUrl?: string; authAudience?: string; }) => { await analytics.track(TelemetryEvent.CLI_COMMAND, { command: "default", protocol: options.protocol, port: options.port, host: options.host, resume: options.resume, readOnly: options.readOnly, authEnabled: !!options.authEnabled, }); // Resolve protocol and validate flags const resolvedProtocol = resolveProtocol(options.protocol); if (resolvedProtocol === "stdio") { setLogLevel(LogLevel.ERROR); // Force quiet logging in stdio mode } logger.debug("No subcommand specified, starting unified server by default..."); const port = validatePort(options.port); const host = validateHost(options.host); // Parse and validate auth configuration const authConfig = parseAuthConfig({ authEnabled: options.authEnabled, authIssuerUrl: options.authIssuerUrl, authAudience: options.authAudience, }); if (authConfig) { validateAuthConfig(authConfig); warnHttpUsage(authConfig, port); } // Get global options from the command itself (default action runs on root command) const globalOptions = program.opts(); // Ensure browsers are installed ensurePlaywrightBrowsersInstalled(); // Resolve embedding configuration for local execution (default action needs embeddings) const embeddingConfig = resolveEmbeddingContext(options.embeddingModel); const docService = await createLocalDocumentManagement( globalOptions.storePath, embeddingConfig, ); const pipelineOptions: PipelineOptions = { recoverJobs: options.resume || false, // Use --resume flag for job recovery concurrency: 3, }; const pipeline = await createPipelineWithCallbacks(docService, pipelineOptions); if (resolvedProtocol === "stdio") { // Direct stdio mode - bypass AppServer entirely logger.debug(`Auto-detected stdio protocol (no TTY)`); await pipeline.start(); // Start pipeline for stdio mode const mcpTools = await initializeTools(docService, pipeline); const mcpServer = await startStdioServer(mcpTools, options.readOnly); // Register for graceful shutdown (stdio mode) registerGlobalServices({ mcpStdioServer: mcpServer, docService, pipeline, }); await new Promise(() => {}); // Keep running forever } else { // HTTP mode - use AppServer logger.debug(`Auto-detected http protocol (TTY available)`); // Configure services based on resolved protocol const config = createAppServerConfig({ enableWebInterface: true, // Enable web interface in http mode enableMcpServer: true, // Always enable MCP server enableApiServer: true, // Enable API (tRPC) in http mode enableWorker: true, // Always enable in-process worker for unified server port, host, readOnly: options.readOnly, auth: authConfig, startupContext: { cliCommand: "default", mcpProtocol: "http", }, }); const appServer = await startAppServer(docService, pipeline, config); // Register for graceful shutdown (http mode) // Note: pipeline is managed by AppServer, so don't register it globally registerGlobalServices({ appServer, docService, // pipeline is owned by AppServer - don't register globally to avoid double shutdown }); await new Promise(() => {}); // Keep running forever } }, ) ); }

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/arabold/docs-mcp-server'

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