Figma MCP Server
by deepsuthar496
Verified
#!/usr/bin/env node
import { Server } from '@modelcontextprotocol/sdk/server/index.js';
import { StdioServerTransport } from '@modelcontextprotocol/sdk/server/stdio.js';
import {
CallToolRequestSchema,
ListToolsRequestSchema,
ErrorCode,
McpError,
} from '@modelcontextprotocol/sdk/types.js';
import axios, { AxiosInstance } from 'axios';
interface FigmaConfig {
accessToken: string;
teamId?: string;
}
class FigmaServer {
private server: Server;
private axiosInstance: AxiosInstance;
constructor(config: FigmaConfig) {
this.server = new Server(
{
name: 'figma-mcp',
version: '0.1.0',
},
{
capabilities: {
tools: {},
},
}
);
this.axiosInstance = axios.create({
baseURL: 'https://api.figma.com/v1',
headers: {
'X-Figma-Token': config.accessToken,
},
});
this.setupToolHandlers();
this.server.onerror = (error) => console.error('[MCP Error]', error);
process.on('SIGINT', async () => {
await this.server.close();
process.exit(0);
});
}
private setupToolHandlers() {
this.server.setRequestHandler(CallToolRequestSchema, async (request) => {
try {
switch (request.params.name) {
case 'get_file':
return await this.getFile(request.params.arguments);
case 'get_file_comments':
return await this.getFileComments(request.params.arguments);
case 'post_comment':
return await this.postComment(request.params.arguments);
case 'delete_comment':
return await this.deleteComment(request.params.arguments);
case 'get_team_projects':
return await this.getTeamProjects(request.params.arguments);
case 'get_project_files':
return await this.getProjectFiles(request.params.arguments);
case 'get_file_components':
return await this.getFileComponents(request.params.arguments);
case 'get_component_styles':
return await this.getComponentStyles(request.params.arguments);
case 'get_file_versions':
return await this.getFileVersions(request.params.arguments);
case 'create_webhook':
return await this.createWebhook(request.params.arguments);
case 'get_webhooks':
return await this.getWebhooks(request.params.arguments);
case 'delete_webhook':
return await this.deleteWebhook(request.params.arguments);
default:
throw new McpError(
ErrorCode.MethodNotFound,
`Unknown tool: ${request.params.name}`
);
}
} catch (error) {
if (axios.isAxiosError(error)) {
return {
content: [
{
type: 'text',
text: `Figma API error: ${
error.response?.data.message ?? error.message
}`,
},
],
isError: true,
};
}
throw error;
}
});
this.server.setRequestHandler(ListToolsRequestSchema, async () => ({
tools: [
{
name: 'get_file',
description: 'Get information about a Figma file',
inputSchema: {
type: 'object',
properties: {
file_key: {
type: 'string',
description: 'The Figma file key',
},
},
required: ['file_key'],
},
},
{
name: 'get_file_comments',
description: 'Get comments from a Figma file',
inputSchema: {
type: 'object',
properties: {
file_key: {
type: 'string',
description: 'The Figma file key',
},
},
required: ['file_key'],
},
},
{
name: 'post_comment',
description: 'Post a comment to a Figma file',
inputSchema: {
type: 'object',
properties: {
file_key: {
type: 'string',
description: 'The Figma file key',
},
message: {
type: 'string',
description: 'The comment message',
},
},
required: ['file_key', 'message'],
},
},
{
name: 'delete_comment',
description: 'Delete a comment from a Figma file',
inputSchema: {
type: 'object',
properties: {
file_key: {
type: 'string',
description: 'The Figma file key',
},
comment_id: {
type: 'string',
description: 'The comment ID',
},
},
required: ['file_key', 'comment_id'],
},
},
{
name: 'get_team_projects',
description: 'Get projects for a team',
inputSchema: {
type: 'object',
properties: {
team_id: {
type: 'string',
description: 'The team ID',
},
},
required: ['team_id'],
},
},
{
name: 'get_project_files',
description: 'Get files in a project',
inputSchema: {
type: 'object',
properties: {
project_id: {
type: 'string',
description: 'The project ID',
},
},
required: ['project_id'],
},
},
{
name: 'get_file_components',
description: 'Get components in a file',
inputSchema: {
type: 'object',
properties: {
file_key: {
type: 'string',
description: 'The Figma file key',
},
},
required: ['file_key'],
},
},
{
name: 'get_component_styles',
description: 'Get published styles',
inputSchema: {
type: 'object',
properties: {
team_id: {
type: 'string',
description: 'The team ID',
},
},
required: ['team_id'],
},
},
{
name: 'get_file_versions',
description: 'Get version history of a file',
inputSchema: {
type: 'object',
properties: {
file_key: {
type: 'string',
description: 'The Figma file key',
},
},
required: ['file_key'],
},
},
{
name: 'create_webhook',
description: 'Create a webhook',
inputSchema: {
type: 'object',
properties: {
team_id: {
type: 'string',
description: 'The team ID',
},
event_type: {
type: 'string',
description: 'The event type to listen for',
},
callback_url: {
type: 'string',
description: 'The callback URL',
},
},
required: ['team_id', 'event_type', 'callback_url'],
},
},
{
name: 'get_webhooks',
description: 'List webhooks',
inputSchema: {
type: 'object',
properties: {
team_id: {
type: 'string',
description: 'The team ID',
},
},
required: ['team_id'],
},
},
{
name: 'delete_webhook',
description: 'Delete a webhook',
inputSchema: {
type: 'object',
properties: {
webhook_id: {
type: 'string',
description: 'The webhook ID',
},
},
required: ['webhook_id'],
},
},
],
}));
}
private async getFile(args: any) {
const response = await this.axiosInstance.get(`/files/${args.file_key}`);
return {
content: [
{
type: 'text',
text: JSON.stringify(response.data, null, 2),
},
],
};
}
private async getFileComments(args: any) {
const response = await this.axiosInstance.get(`/files/${args.file_key}/comments`);
return {
content: [
{
type: 'text',
text: JSON.stringify(response.data, null, 2),
},
],
};
}
private async postComment(args: any) {
const response = await this.axiosInstance.post(`/files/${args.file_key}/comments`, {
message: args.message,
});
return {
content: [
{
type: 'text',
text: JSON.stringify(response.data, null, 2),
},
],
};
}
private async deleteComment(args: any) {
await this.axiosInstance.delete(`/files/${args.file_key}/comments/${args.comment_id}`);
return {
content: [
{
type: 'text',
text: 'Comment deleted successfully',
},
],
};
}
private async getTeamProjects(args: any) {
const response = await this.axiosInstance.get(`/teams/${args.team_id}/projects`);
return {
content: [
{
type: 'text',
text: JSON.stringify(response.data, null, 2),
},
],
};
}
private async getProjectFiles(args: any) {
const response = await this.axiosInstance.get(`/projects/${args.project_id}/files`);
return {
content: [
{
type: 'text',
text: JSON.stringify(response.data, null, 2),
},
],
};
}
private async getFileComponents(args: any) {
const response = await this.axiosInstance.get(`/files/${args.file_key}/components`);
return {
content: [
{
type: 'text',
text: JSON.stringify(response.data, null, 2),
},
],
};
}
private async getComponentStyles(args: any) {
const response = await this.axiosInstance.get(`/teams/${args.team_id}/styles`);
return {
content: [
{
type: 'text',
text: JSON.stringify(response.data, null, 2),
},
],
};
}
private async getFileVersions(args: any) {
const response = await this.axiosInstance.get(`/files/${args.file_key}/versions`);
return {
content: [
{
type: 'text',
text: JSON.stringify(response.data, null, 2),
},
],
};
}
private async createWebhook(args: any) {
const response = await this.axiosInstance.post(`/teams/${args.team_id}/webhooks`, {
event_type: args.event_type,
callback_url: args.callback_url,
});
return {
content: [
{
type: 'text',
text: JSON.stringify(response.data, null, 2),
},
],
};
}
private async getWebhooks(args: any) {
const response = await this.axiosInstance.get(`/teams/${args.team_id}/webhooks`);
return {
content: [
{
type: 'text',
text: JSON.stringify(response.data, null, 2),
},
],
};
}
private async deleteWebhook(args: any) {
await this.axiosInstance.delete(`/webhooks/${args.webhook_id}`);
return {
content: [
{
type: 'text',
text: 'Webhook deleted successfully',
},
],
};
}
async run() {
const transport = new StdioServerTransport();
await this.server.connect(transport);
console.error('Figma MCP server running on stdio');
}
}
const ACCESS_TOKEN = process.env.FIGMA_ACCESS_TOKEN;
if (!ACCESS_TOKEN) {
throw new Error('FIGMA_ACCESS_TOKEN environment variable is required');
}
const server = new FigmaServer({
accessToken: ACCESS_TOKEN,
});
server.run().catch(console.error);