Vercel MCP Server

import { z } from "zod"; import { handleResponse } from "../utils/response.js"; import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js"; import { BASE_URL, DEFAULT_ACCESS_TOKEN } from "../config/constants.js"; export function registerUserTools(server: McpServer) { // Delete User Account server.tool( "delete_user", "Initiates the deletion process for the currently authenticated User", { reasons: z.array( z.object({ slug: z.string().describe("Reason identifier"), description: z.string().describe("Detailed description of the reason") }) ).optional().describe("Optional array of objects that describe the reason why the User account is being deleted") }, async ({ reasons }) => { const response = await fetch(`${BASE_URL}/v1/user`, { method: "DELETE", headers: { "Content-Type": "application/json", Authorization: `Bearer ${DEFAULT_ACCESS_TOKEN}`, }, ...(reasons && { body: JSON.stringify({ reasons }) }) }); const data = await handleResponse(response); return { content: [ { type: "text", text: `User deletion initiated:\n${JSON.stringify(data, null, 2)}` }, ], }; } ); // Get User Information server.tool( "get_user", "Retrieves information related to the currently authenticated User", {}, async () => { const response = await fetch(`${BASE_URL}/v2/user`, { headers: { Authorization: `Bearer ${DEFAULT_ACCESS_TOKEN}`, }, }); const data = await handleResponse(response); return { content: [ { type: "text", text: `User information:\n${JSON.stringify(data, null, 2)}` }, ], }; } ); // List User Events server.tool( "list_user_events", "Retrieves a list of events generated by the User on Vercel", { limit: z.number().optional().describe("Maximum number of items which may be returned"), since: z.string().optional().describe("Timestamp to only include items created since then (e.g. 2019-12-08T10:00:38.976Z)"), until: z.string().optional().describe("Timestamp to only include items created until then (e.g. 2019-12-09T23:00:38.976Z)"), types: z.string().optional().describe("Comma-delimited list of event types to filter the results by (e.g. login,team-member-join,domain-buy)"), userId: z.string().optional().describe("When retrieving events for a Team, filter events by a specific member"), withPayload: z.string().optional().describe("When set to true, includes the payload field for each event"), teamId: z.string().optional().describe("The Team identifier to perform the request on behalf of"), slug: z.string().optional().describe("The Team slug to perform the request on behalf of") }, async ({ limit, since, until, types, userId, withPayload, teamId, slug }) => { const url = new URL(`${BASE_URL}/v3/events`); if (limit) url.searchParams.append("limit", limit.toString()); if (since) url.searchParams.append("since", since); if (until) url.searchParams.append("until", until); if (types) url.searchParams.append("types", types); if (userId) url.searchParams.append("userId", userId); if (withPayload) url.searchParams.append("withPayload", withPayload); if (teamId) url.searchParams.append("teamId", teamId); if (slug) url.searchParams.append("slug", slug); const response = await fetch(url.toString(), { headers: { Authorization: `Bearer ${DEFAULT_ACCESS_TOKEN}`, }, }); const data = await handleResponse(response); return { content: [ { type: "text", text: `User events:\n${JSON.stringify(data, null, 2)}` }, ], }; } ); }