Skip to main content
Glama

Convex MCP server

Official
by get-convex
messages.ts6.08 kB
import { action, internalQuery, mutation } from "./_generated/server"; import { query } from "./_generated/server"; import { api, internal, components } from "./_generated/api"; import { Doc } from "./_generated/dataModel"; import { v } from "convex/values"; import { createFunctionHandle, FunctionHandle } from "convex/server"; import { functionValidator } from "./types"; import { add } from "@convex-dev/ratelimiter"; export const list = query(async (ctx): Promise<Doc<"messages">[]> => { const result = await ctx.runQuery( components.waitlist.index.sayGoodbyeFromQuery, {}, ); console.log(result); return await ctx.db.query("messages").collect(); }); export const getFunctionHandle = query(async () => { const handle: string = await createFunctionHandle(api.messages.list); return handle; }); export const getChildFunctionHandle = query(async () => { const handle: string = await createFunctionHandle( components.waitlist.index.listFiles, ); return handle; }); export const getFunctionHandleAction = action(async () => { const handle: string = await createFunctionHandle(api.messages.list); return handle as string; }); export const sumNumbers = internalQuery({ args: { a: v.number(), b: v.number(), }, handler: async (_, args) => { return args.a + args.b; }, }); export const getSumNumbers = query(async () => { const handle: string = await createFunctionHandle( internal.messages.sumNumbers, ); return handle; }); export const takeInHandle = query({ args: { a: v.number(), b: v.number(), handle: functionValidator< FunctionHandle<"query", { a: number; b: number }, number> >(), }, handler: async (ctx, args) => { const result = await ctx.runQuery(args.handle, { a: args.a, b: args.b }); return result; }, }); export const storeHandle = mutation(async (ctx) => { const handle = await createFunctionHandle(internal.messages.sumNumbers); await ctx.db.insert("functionHandles", { untyped: handle, typed: handle, }); for await (const document of ctx.db.query("functionHandles")) { const typedResult = await ctx.runQuery(document.typed, { a: 2, b: 3, }); const untypedResult = await ctx.runQuery(document.untyped, { a: 4, b: 5, }); console.log({ typedResult, untypedResult }); } }); export const send = mutation( async (ctx, { body, author }: { body: string; author: string }) => { const result = await ctx.runMutation( components.ratelimiter.index.rateLimit, { name: "send", key: author, }, ); // TODO: Output validators need to support non-object types to have a // more precise union type here. if (!result.ok) { const waitTime = result.retryAt! - Date.now(); const asSec = Math.round(waitTime / 1000).toFixed(2); throw new Error(`Rate limit exceeded, please try again in ${asSec}s.`); } console.log(result); const message = { body, author }; await ctx.db.insert("messages", message); }, ); export const save = action({ args: { message: v.string() }, returns: v.string(), handler: async (ctx, { message }) => { return ctx.runAction(components.waitlist.index.storeInFile, { message }); }, }); export const readSaved = action({ args: { id: v.string() }, returns: v.string(), handler: async (ctx, args) => { const files = await ctx.runQuery(api.messages.listFiles); console.log("files", files); const innerFiles = await ctx.runQuery(components.waitlist.index.listFiles); console.log("inner files", innerFiles); return ctx.runAction(components.waitlist.index.readFromFile, { id: args.id, }); }, }); export const listFiles = query(async (ctx) => { return await ctx.db.system.query("_storage").collect(); }); export const fileUploadUrl = mutation({ args: {}, returns: v.string(), handler: async (ctx) => { return ctx.runMutation(components.waitlist.index.fileUploadUrl, {}); }, }); export const fileDownloadUrl = query({ args: { id: v.string() }, returns: v.string(), handler: async (ctx, { id }) => { return ctx.runQuery(components.waitlist.index.fileDownloadUrl, { id }); }, }); export const componentTest = action(async (ctx) => { console.log("calling into component..."); const response = await ctx.runAction( components.waitlist.index.repeatMessage, { message: "hello", n: 3, }, ); console.log("received response from component:", response); return response; }); export const componentTest2 = action(async (ctx) => { console.log("calling into component..."); const response = await ctx.runAction(components.waitlist.actionDemo.demo, {}); console.log("received response from component:", response); return response; }); export const startCron = mutation(async (ctx) => { console.log("starting cron job..."); await ctx.runMutation(components.waitlist.index.scheduleMessage, {}); console.log("cron job started"); }); export const getMessageCount = query(async (ctx) => { return ctx.runQuery(components.waitlist.index.getMessageCount, {}); }); export const scheduleSendWaitlistMessage = mutation(async (ctx) => { console.log("scheduling message"); await ctx.scheduler.runAfter( 30 * 1000, components.waitlist.index.scheduleMessage, {}, ); console.log(await ctx.db.system.query("_scheduled_functions").collect()); return "scheduled"; }); export const testPartialRollback = mutation(async (ctx) => { const initialResult = await ctx.runQuery( components.waitlist.index.latestWrite, {}, ); console.log(initialResult); await ctx.runMutation(components.waitlist.index.writeSuccessfully, { text: "hello", }); try { await ctx.runMutation(components.waitlist.index.writeThenFail, { text: "world", }); } catch (e) { console.log("caught error", e); } const result = await ctx.runQuery(components.waitlist.index.latestWrite, {}); console.log(result); }); const rlClient = add(1, 2); console.log(rlClient);

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