Skip to main content
Glama

Convex MCP server

Official
by get-convex
protocol.ts6.04 kB
import { Key, MutationId } from "local-store/shared/types"; import { LowerBound, PageResult, UpperBound } from "local-store/shared/types"; import { MutationInfo } from "local-store/shared/types"; import { MAXIMAL_KEY, MINIMAL_KEY, PersistId } from "local-store/shared/types"; import { webSockets } from "./websocket"; import { convexToJson, jsonToConvex } from "convex/values"; import { FunctionReference, getFunctionName } from "convex/server"; import { Page } from "local-store/browser/core/protocol"; import { localPersistence } from "./indexedDb"; export type MutationInfoJSON = { mutationName: string; mutationId: string; mutationPath: string; // serialized via convexToJson optUpdateArgs: any; // serialized via convexToJson serverArgs: any; }; export type PageJSON = { tableName: string; indexName: string; convexSubscriptionId: string; state: | { kind: "loaded"; value: PageResultJSON } | { kind: "loading"; target: KeyJSON }; }; export type PageResultJSON = { // serialized via convexToJson results: any[]; lowerBound: LowerBoundJSON; upperBound: UpperBoundJSON; }; export type LowerBoundJSON = | { kind: "successor"; value: IndexPrefixJSON } | typeof MINIMAL_KEY; // serialized via convexToJson export type IndexPrefixJSON = any[]; export type UpperBoundJSON = ExactKeyJSON | typeof MAXIMAL_KEY; export type ExactKeyJSON = { kind: "exact"; value: IndexKeyJSON; }; // serialized via convexToJson export type IndexKeyJSON = any[]; export type KeyJSON = | { kind: "successor" | "predecessor"; value: IndexPrefixJSON } | ExactKeyJSON; type OutgoingMessage = // WebSocket messages | { type: "connect"; webSocketId: number } | { type: "send"; webSocketId: number; data: string; } | { type: "close"; webSocketId: number } // Persistence messages | { type: "persistMutation"; persistId: string; mutationInfo: MutationInfoJSON; } | { type: "persistPages"; persistId: string; pages: Array<PageJSON>; } | { type: "mutationDone"; mutationId: number; result: | { type: "success"; value: any } | { type: "failure"; error: string }; }; export const outgoingMessages: OutgoingMessage[] = []; export type IncomingMessage = // WebSocket messages | { type: "connected"; webSocketId: number } | { type: "message"; webSocketId: number; data: string } | { type: "closed"; webSocketId: number } // Persistence messages | { type: "persistenceDone"; persistId: string; error?: string }; export function getOutgoingMessages() { const result = [...outgoingMessages]; outgoingMessages.length = 0; return result; } export function receiveIncomingMessages(messages: IncomingMessage[]) { for (const message of messages) { switch (message.type) { case "connected": { const ws = webSockets.get(message.webSocketId); if (!ws) { throw new Error(`Unknown websocket id: ${message.webSocketId}`); } if (ws.onopen) { ws.onopen(new Event("open")); } break; } case "message": { const ws = webSockets.get(message.webSocketId); if (!ws) { throw new Error(`Unknown websocket id: ${message.webSocketId}`); } if (ws.onmessage) { ws.onmessage({ data: message.data } as any); } break; } case "closed": { const ws = webSockets.get(message.webSocketId); if (!ws) { throw new Error(`Unknown websocket id: ${message.webSocketId}`); } if (ws.onclose) { ws.onclose({ code: 1000 } as any); } webSockets.delete(message.webSocketId); break; } case "persistenceDone": { localPersistence.emitMessage({ requestor: "LocalPersistence", kind: "localPersistComplete", persistId: message.persistId as PersistId, }); break; } default: { message satisfies never; } } } } export function mutationInfoToJson( mutationInfo: MutationInfo, ): MutationInfoJSON { return { mutationName: mutationInfo.mutationName, mutationId: mutationInfo.mutationId, mutationPath: getFunctionName(mutationInfo.mutationPath), optUpdateArgs: convexToJson(mutationInfo.optUpdateArgs as any), serverArgs: convexToJson(mutationInfo.serverArgs as any), }; } export function parseMutationInfoJson( mutationInfoJson: MutationInfoJSON, ): MutationInfo { return { mutationName: mutationInfoJson.mutationName, mutationId: mutationInfoJson.mutationId as MutationId, mutationPath: mutationInfoJson.mutationPath as unknown as FunctionReference<"mutation">, optUpdateArgs: jsonToConvex(mutationInfoJson.optUpdateArgs) as any, serverArgs: jsonToConvex(mutationInfoJson.serverArgs) as any, }; } export function pageToJson(page: Page): PageJSON { let state: PageJSON["state"]; if (page.state.kind === "loaded") { state = { kind: "loaded", value: pageResultToJson(page.state.value) }; } else { state = { kind: "loading", target: keyToJson(page.state.target) }; } return { tableName: page.tableName, indexName: page.indexName, convexSubscriptionId: page.convexSubscriptionId, state, }; } function pageResultToJson(pageResult: PageResult): PageResultJSON { return { results: pageResult.results, lowerBound: lowerBoundToJson(pageResult.lowerBound), upperBound: upperBoundToJson(pageResult.upperBound), }; } function lowerBoundToJson(lowerBound: LowerBound): LowerBoundJSON { return { kind: lowerBound.kind, value: convexToJson(lowerBound.value as any) as any, }; } function upperBoundToJson(upperBound: UpperBound): UpperBoundJSON { return { kind: upperBound.kind, value: convexToJson(upperBound.value as any) as any, }; } function keyToJson(key: Key): KeyJSON { return { kind: key.kind, value: convexToJson(key.value as any) as any, }; }

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/get-convex/convex-backend'

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