Skip to main content
Glama
macuse-client.ts5.54 kB
import { spawn } from "node:child_process"; import { Client } from "@modelcontextprotocol/sdk/client/index.js"; import { SSEClientTransport } from "@modelcontextprotocol/sdk/client/sse.js"; import { StdioClientTransport } from "@modelcontextprotocol/sdk/client/stdio.js"; import { StreamableHTTPClientTransport } from "@modelcontextprotocol/sdk/client/streamableHttp.js"; import { config } from "../config.js"; import { type MacuseTransportConfig, resolveMacuseTransport, } from "./resolver.js"; // biome-ignore lint/suspicious/noTemplateCurlyInString: This is a literal string placeholder, not a template const ACCESS_TOKEN_PLACEHOLDER = "${ACCESS_TOKEN}"; export class MacuseClient { private client: Client | null = null; private transport: | StdioClientTransport | SSEClientTransport | StreamableHTTPClientTransport | null = null; private transportConfig: MacuseTransportConfig | null = null; async connect(): Promise<void> { const result = await resolveMacuseTransport(); if (!result.success || !result.transport) { const errorMsg = result.error ?? "Unknown error"; const platform = process.platform; if (/macos.*only|darwin.*only/i.test(errorMsg) || platform !== "darwin") { throw new Error( `Macuse supports macOS only. Current platform: ${platform}`, ); } if (/executable not found/i.test(errorMsg)) { if (platform === "darwin") { this.openDownloadPage(); // Provide a clear, user-facing message throw new Error( "Macuse executable not found. Opened https://macuse.app/download/ in your browser. Please install and try again.", ); } throw new Error( `Macuse supports macOS only. Current platform: ${platform}`, ); } throw new Error(`Failed to resolve Macuse transport: ${errorMsg}`); } this.transportConfig = result.transport; await this.createTransport(); if (this.transport) { await this.client?.connect(this.transport); } } private async createTransport(): Promise<void> { if (!this.transportConfig) { throw new Error("Transport config not available"); } const accessToken = config.accessToken; if (!accessToken) { throw new Error("ACCESS_TOKEN not provided"); } switch (this.transportConfig.mode) { case "streamableHttp": { const url = this.transportConfig.config.url; if (!url) { throw new Error("URL not provided for streamableHttp transport"); } // Replace token placeholder in headers const headers = { ...this.transportConfig.config.headers }; if (headers.Authorization?.includes(ACCESS_TOKEN_PLACEHOLDER)) { headers.Authorization = headers.Authorization.replace( ACCESS_TOKEN_PLACEHOLDER, accessToken, ); } this.transport = new StreamableHTTPClientTransport(new URL(url), { requestInit: { headers, }, }); break; } case "sse": { const url = this.transportConfig.config.url; if (!url) { throw new Error("URL not provided for SSE transport"); } const headers = { ...this.transportConfig.config.headers }; if (headers.Authorization?.includes(ACCESS_TOKEN_PLACEHOLDER)) { headers.Authorization = headers.Authorization.replace( ACCESS_TOKEN_PLACEHOLDER, accessToken, ); } this.transport = new SSEClientTransport(new URL(url), { requestInit: { headers, }, }); break; } case "stdio": { this.transport = new StdioClientTransport({ command: config.macuseBinary, args: ["--stdio"], env: { ...process.env, ACCESS_TOKEN: accessToken, }, }); break; } default: throw new Error( `Unsupported transport mode: ${this.transportConfig.mode}`, ); } this.client = new Client( { name: "macuse-mcp-proxy", version: __VERSION__, }, { capabilities: { tools: {}, }, }, ); } async listTools() { if (!this.client) throw new Error("Client not connected"); return await this.client.listTools(); } async callTool(name: string, arguments_: Record<string, unknown>) { if (!this.client) throw new Error("Client not connected"); return await this.client.callTool({ name, arguments: arguments_, }); } async close(): Promise<void> { if (this.client) { await this.client.close(); this.client = null; } this.transport = null; this.transportConfig = null; } private openDownloadPage() { const url = "https://macuse.app/download/"; // macOS: open, Linux: xdg-open, Windows: start const platform = process.platform; try { if (platform === "darwin") { spawn("open", [url], { stdio: "ignore", detached: true }).unref(); } // eslint-disable-next-line no-console console.error( `Macuse is not installed. Download from: ${url} \nAfter installing, rerun this command.`, ); } catch { // As a fallback, at least print the URL // eslint-disable-next-line no-console console.error( `Macuse is not installed. Please open and download: ${url}`, ); } } }

Latest Blog Posts

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/macuse-app/macuse'

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