@mrfentmen/figma-mcp 1.0.0 → 1.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -4,9 +4,17 @@ Query the Figma API (token; set FIGMA_ACCESS_TOKEN, X-Figma-Token): profile, fil
4
4
 
5
5
  ## Tools
6
6
 
7
- - `me` — Figma user.
8
- - `get_file` — File metadata.
9
- - `project_files` — Files in a project.
7
+ - `me` — The Figma user the access token belongs to.
8
+ - `get_file` — File metadata: name, pages and last modified date.
9
+ - `project_files` — Figma files inside one project id.
10
+
11
+ - `team_projects` — Projects in a team.
12
+ - `file_comments` — Comments on a file.
13
+ - `file_versions` — Version history.
14
+ - `file_components` — Published components.
15
+ - `file_styles` — Published styles.
16
+ - `file_nodes` — Nodes by IDs.
17
+ - `file_images` — PNG renders.
10
18
 
11
19
  ## Source
12
20
 
package/dist/api.d.ts ADDED
@@ -0,0 +1,14 @@
1
+ export declare class FigmaError extends Error {
2
+ constructor(message: string);
3
+ }
4
+ export declare function errorMessage(e: unknown): string;
5
+ export declare function me(): Promise<string>;
6
+ export declare function getFile(fileKey: string): Promise<string>;
7
+ export declare function projectFiles(projectId: string): Promise<string>;
8
+ export declare function teamProjects(teamId: string): Promise<string>;
9
+ export declare function fileComments(fileKey: string): Promise<string>;
10
+ export declare function fileVersions(fileKey: string): Promise<string>;
11
+ export declare function fileComponents(fileKey: string): Promise<string>;
12
+ export declare function fileStyles(fileKey: string): Promise<string>;
13
+ export declare function fileNodes(fileKey: string, nodeIds: string): Promise<string>;
14
+ export declare function fileImages(fileKey: string, nodeIds: string): Promise<string>;
package/dist/api.js ADDED
@@ -0,0 +1,63 @@
1
+ export class FigmaError extends Error {
2
+ constructor(message) {
3
+ super(message);
4
+ this.name = "FigmaError";
5
+ }
6
+ }
7
+ export function errorMessage(e) {
8
+ return e instanceof Error ? e.message : String(e);
9
+ }
10
+ const UA = { "User-Agent": "awesome-mcps/1.0" };
11
+ function headers() {
12
+ const k = process.env.FIGMA_ACCESS_TOKEN;
13
+ if (!k)
14
+ throw new FigmaError("Set FIGMA_ACCESS_TOKEN (Figma personal token).");
15
+ return { ...UA, Accept: "application/json", "X-Figma-Token": k };
16
+ }
17
+ async function get(path) {
18
+ let res;
19
+ try {
20
+ res = await fetch("https://api.figma.com/v1" + path, {
21
+ headers: headers(),
22
+ signal: AbortSignal.timeout(25000),
23
+ });
24
+ }
25
+ catch (e) {
26
+ throw new FigmaError(`Network error: ${e.message}`);
27
+ }
28
+ if (!res.ok) {
29
+ const body = (await res.text()).slice(0, 300);
30
+ throw new FigmaError(`HTTP ${res.status}: ${body}`);
31
+ }
32
+ return (await res.text()).slice(0, 12000);
33
+ }
34
+ export function me() {
35
+ return get("/me");
36
+ }
37
+ export function getFile(fileKey) {
38
+ return get(`/files/${encodeURIComponent(fileKey)}`);
39
+ }
40
+ export function projectFiles(projectId) {
41
+ return get(`/projects/${encodeURIComponent(projectId)}/files`);
42
+ }
43
+ export function teamProjects(teamId) {
44
+ return get(`/teams/${encodeURIComponent(teamId)}/projects`);
45
+ }
46
+ export function fileComments(fileKey) {
47
+ return get(`/files/${encodeURIComponent(fileKey)}/comments`);
48
+ }
49
+ export function fileVersions(fileKey) {
50
+ return get(`/files/${encodeURIComponent(fileKey)}/versions`);
51
+ }
52
+ export function fileComponents(fileKey) {
53
+ return get(`/files/${encodeURIComponent(fileKey)}/components`);
54
+ }
55
+ export function fileStyles(fileKey) {
56
+ return get(`/files/${encodeURIComponent(fileKey)}/styles`);
57
+ }
58
+ export function fileNodes(fileKey, nodeIds) {
59
+ return get(`/files/${encodeURIComponent(fileKey)}/nodes?ids=${encodeURIComponent(nodeIds)}`);
60
+ }
61
+ export function fileImages(fileKey, nodeIds) {
62
+ return get(`/files/${encodeURIComponent(fileKey)}/images?ids=${encodeURIComponent(nodeIds)}&format=png`);
63
+ }
@@ -0,0 +1 @@
1
+ export {};
package/dist/index.js ADDED
@@ -0,0 +1,12 @@
1
+ import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
2
+ import { createServer } from "./server.js";
3
+ async function main() {
4
+ const server = createServer();
5
+ const transport = new StdioServerTransport();
6
+ await server.connect(transport);
7
+ console.error("MCP server running on stdio");
8
+ }
9
+ main().catch((err) => {
10
+ console.error("Fatal error:", err);
11
+ process.exit(1);
12
+ });
@@ -0,0 +1,2 @@
1
+ import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
2
+ export declare function createServer(): McpServer;
package/dist/server.js ADDED
@@ -0,0 +1,163 @@
1
+ import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
2
+ import { z } from "zod";
3
+ import { errorMessage, me, getFile, projectFiles, teamProjects, fileComments, fileVersions, fileComponents, fileStyles, fileNodes, fileImages, } from "./api.js";
4
+ const text = (t) => ({ content: [{ type: "text", text: t }] });
5
+ const textError = (t) => ({ content: [{ type: "text", text: t }], isError: true });
6
+ const READ_ONLY = { readOnlyHint: true, openWorldHint: true };
7
+ export function createServer() {
8
+ const server = new McpServer({
9
+ name: "figma-mcp",
10
+ version: "1.0.0",
11
+ });
12
+ server.registerTool("me", {
13
+ title: "My profile",
14
+ description: "The Figma user the access token belongs to.",
15
+ inputSchema: z.object({}),
16
+ annotations: READ_ONLY,
17
+ }, async ({}) => {
18
+ try {
19
+ return text(await me());
20
+ }
21
+ catch (e) {
22
+ return textError(errorMessage(e));
23
+ }
24
+ });
25
+ server.registerTool("get_file", {
26
+ title: "Get file",
27
+ description: "File metadata: name, pages and last modified date.",
28
+ inputSchema: z.object({
29
+ file_key: z.string().describe("File key from URL.")
30
+ }),
31
+ annotations: READ_ONLY,
32
+ }, async ({ file_key }) => {
33
+ try {
34
+ return text(await getFile(file_key));
35
+ }
36
+ catch (e) {
37
+ return textError(errorMessage(e));
38
+ }
39
+ });
40
+ server.registerTool("project_files", {
41
+ title: "Project files",
42
+ description: "Figma files inside one project id.",
43
+ inputSchema: z.object({
44
+ project_id: z.string().describe("Project ID from the Figma URL")
45
+ }),
46
+ annotations: READ_ONLY,
47
+ }, async ({ project_id }) => {
48
+ try {
49
+ return text(await projectFiles(project_id));
50
+ }
51
+ catch (e) {
52
+ return textError(errorMessage(e));
53
+ }
54
+ });
55
+ server.registerTool("team_projects", {
56
+ title: "Team projects",
57
+ description: "Projects in a team.",
58
+ inputSchema: z.object({
59
+ team_id: z.string().describe("Team ID.")
60
+ }),
61
+ annotations: READ_ONLY,
62
+ }, async ({ team_id }) => {
63
+ try {
64
+ return text(await teamProjects(team_id));
65
+ }
66
+ catch (e) {
67
+ return textError(errorMessage(e));
68
+ }
69
+ });
70
+ server.registerTool("file_comments", {
71
+ title: "File comments",
72
+ description: "Comments on a file.",
73
+ inputSchema: z.object({
74
+ file_key: z.string().describe("File key.")
75
+ }),
76
+ annotations: READ_ONLY,
77
+ }, async ({ file_key }) => {
78
+ try {
79
+ return text(await fileComments(file_key));
80
+ }
81
+ catch (e) {
82
+ return textError(errorMessage(e));
83
+ }
84
+ });
85
+ server.registerTool("file_versions", {
86
+ title: "File versions",
87
+ description: "Version history.",
88
+ inputSchema: z.object({
89
+ file_key: z.string().describe("File key.")
90
+ }),
91
+ annotations: READ_ONLY,
92
+ }, async ({ file_key }) => {
93
+ try {
94
+ return text(await fileVersions(file_key));
95
+ }
96
+ catch (e) {
97
+ return textError(errorMessage(e));
98
+ }
99
+ });
100
+ server.registerTool("file_components", {
101
+ title: "Components",
102
+ description: "Published components.",
103
+ inputSchema: z.object({
104
+ file_key: z.string().describe("File key.")
105
+ }),
106
+ annotations: READ_ONLY,
107
+ }, async ({ file_key }) => {
108
+ try {
109
+ return text(await fileComponents(file_key));
110
+ }
111
+ catch (e) {
112
+ return textError(errorMessage(e));
113
+ }
114
+ });
115
+ server.registerTool("file_styles", {
116
+ title: "Styles",
117
+ description: "Published styles.",
118
+ inputSchema: z.object({
119
+ file_key: z.string().describe("File key.")
120
+ }),
121
+ annotations: READ_ONLY,
122
+ }, async ({ file_key }) => {
123
+ try {
124
+ return text(await fileStyles(file_key));
125
+ }
126
+ catch (e) {
127
+ return textError(errorMessage(e));
128
+ }
129
+ });
130
+ server.registerTool("file_nodes", {
131
+ title: "File nodes",
132
+ description: "Nodes by IDs.",
133
+ inputSchema: z.object({
134
+ file_key: z.string().describe("File key."),
135
+ node_ids: z.string().describe("Comma-separated node IDs.")
136
+ }),
137
+ annotations: READ_ONLY,
138
+ }, async ({ file_key, node_ids }) => {
139
+ try {
140
+ return text(await fileNodes(file_key, node_ids));
141
+ }
142
+ catch (e) {
143
+ return textError(errorMessage(e));
144
+ }
145
+ });
146
+ server.registerTool("file_images", {
147
+ title: "Render nodes",
148
+ description: "PNG renders.",
149
+ inputSchema: z.object({
150
+ file_key: z.string().describe("File key."),
151
+ node_ids: z.string().describe("Comma-separated node IDs.")
152
+ }),
153
+ annotations: READ_ONLY,
154
+ }, async ({ file_key, node_ids }) => {
155
+ try {
156
+ return text(await fileImages(file_key, node_ids));
157
+ }
158
+ catch (e) {
159
+ return textError(errorMessage(e));
160
+ }
161
+ });
162
+ return server;
163
+ }
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@mrfentmen/figma-mcp",
3
- "version": "1.0.0",
4
- "description": "Figma me, files, projects. Token.",
3
+ "version": "1.1.0",
4
+ "description": "Query the Figma API (token; set FIGMA_ACCESS_TOKEN, X-Figma-Token): profile, file details, project files.",
5
5
  "type": "module",
6
6
  "mcpName": "io.github.mrfentmen/figma-mcp",
7
7
  "repository": {