Skip to content

Commit 68d8c1e

Browse files
committed
chore: tighten Cursor plugin compliance and branding
Sync the plugin logo to the canonical LeadMagic icon, validate the manifest against Cursor's official schema, and harden CI so the package stays submission-ready. Made-with: Cursor
1 parent fd1d127 commit 68d8c1e

8 files changed

Lines changed: 235 additions & 51 deletions

File tree

.cursor-plugin/plugin.json

Lines changed: 29 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -1,38 +1,31 @@
11
{
2-
"name": "leadmagic",
3-
"displayName": "LeadMagic",
4-
"version": "0.1.0",
5-
"description": "Official LeadMagic plugin for Cursor with hosted MCP-powered B2B enrichment, contact discovery, company intelligence, and GTM signal research.",
6-
"author": {
7-
"name": "LeadMagic",
8-
"email": "jesse@leadmagic.io"
9-
},
10-
"homepage": "https://leadmagic.io",
11-
"repository": "https://github.com/LeadMagic/leadmagic-cursor-plugin",
12-
"license": "MIT",
13-
"logo": "assets/logo.svg",
14-
"primaryColor": "#0EA5E9",
15-
"keywords": [
16-
"leadmagic",
17-
"cursor",
18-
"mcp",
19-
"b2b",
20-
"data-enrichment",
21-
"email-validation",
22-
"email-finder",
23-
"company-intelligence",
24-
"prospecting",
25-
"gtm"
26-
],
27-
"category": "developer-tools",
28-
"tags": [
29-
"sales",
30-
"prospecting",
31-
"enrichment",
32-
"mcp",
33-
"api"
34-
],
35-
"rules": "./rules/",
36-
"skills": "./skills/",
37-
"mcpServers": "./mcp.json"
2+
"name": "leadmagic",
3+
"displayName": "LeadMagic",
4+
"version": "0.1.0",
5+
"description": "Official LeadMagic plugin for Cursor with hosted MCP-powered B2B enrichment, contact discovery, company intelligence, and GTM signal research.",
6+
"author": {
7+
"name": "LeadMagic",
8+
"email": "jesse@leadmagic.io"
9+
},
10+
"homepage": "https://leadmagic.io",
11+
"repository": "https://github.com/LeadMagic/leadmagic-cursor-plugin",
12+
"license": "MIT",
13+
"logo": "assets/logo.svg",
14+
"keywords": [
15+
"leadmagic",
16+
"cursor",
17+
"mcp",
18+
"b2b",
19+
"data-enrichment",
20+
"email-validation",
21+
"email-finder",
22+
"company-intelligence",
23+
"prospecting",
24+
"gtm"
25+
],
26+
"category": "developer-tools",
27+
"tags": ["sales", "prospecting", "enrichment", "mcp", "api"],
28+
"rules": "./rules/",
29+
"skills": "./skills/",
30+
"mcpServers": "./mcp.json"
3831
}

.github/workflows/validate-plugin.yml

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,9 +11,11 @@ on:
1111
- "assets/**"
1212
- "mcp.json"
1313
- "package.json"
14+
- "package-lock.json"
1415
- "README.md"
1516
- "SUBMISSION.md"
1617
- "rules/**"
18+
- "schemas/**"
1719
- "scripts/**"
1820
- "skills/**"
1921

@@ -31,6 +33,9 @@ jobs:
3133
with:
3234
node-version: "20"
3335

36+
- name: Install dependencies
37+
run: npm ci
38+
3439
- name: Validate plugin package
3540
run: npm run validate
3641

README.md

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -47,6 +47,8 @@ The broader REST API and OpenAPI snapshot include additional surfaces, but this
4747
.github/workflows/validate-plugin.yml
4848
assets/logo.svg
4949
mcp.json
50+
package-lock.json
51+
schemas/plugin.schema.json
5052
rules/leadmagic-usage.mdc
5153
skills/*/SKILL.md
5254
scripts/validate-plugin.mjs
@@ -107,6 +109,8 @@ If you prefer to configure LeadMagic directly in Cursor instead of through the p
107109
npm run validate
108110
```
109111

112+
The validator checks this package against a vendored snapshot of Cursor's official `plugin.schema.json` and then applies LeadMagic-specific assertions for the hosted MCP endpoint, canonical logo asset, and submission metadata.
113+
110114
## Submission
111115

112116
Use `SUBMISSION.md` for ready-to-paste marketplace copy.

SUBMISSION.md

Lines changed: 9 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -4,28 +4,28 @@ Use the following values in the Cursor marketplace publisher form.
44

55
## Form fields
66

7-
**Organization name**
7+
**Organization name**
88
LeadMagic
99

10-
**Organization handle**
10+
**Organization handle**
1111
leadmagic
1212

13-
**Unique namespace**
13+
**Unique namespace**
1414
@leadmagic
1515

16-
**Contact email**
16+
**Contact email**
1717
jesse@leadmagic.io
1818

19-
**Logotype URL**
20-
https://leadmagic.io/icon.svg
19+
**Logotype URL**
20+
https://raw.githubusercontent.com/LeadMagic/leadmagic-cursor-plugin/main/assets/logo.svg
2121

22-
**Description**
22+
**Description**
2323
Official LeadMagic plugin for Cursor. Gives agents direct access to LeadMagic's hosted MCP surface for email validation, email finding, profile enrichment, company intelligence, technographics, competitor research, job-change detection, and hiring-signal workflows.
2424

25-
**GitHub repository**
25+
**GitHub repository**
2626
https://github.com/LeadMagic/leadmagic-cursor-plugin
2727

28-
**Website URL**
28+
**Website URL**
2929
https://leadmagic.io
3030

3131
## Suggested reviewer note

assets/logo.svg

Lines changed: 13 additions & 6 deletions
Loading

package.json

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,5 +9,9 @@
99
"validate:strict": "node scripts/validate-plugin.mjs",
1010
"install:local": "node scripts/install-local-plugin.mjs",
1111
"uninstall:local": "node scripts/install-local-plugin.mjs --unlink"
12+
},
13+
"devDependencies": {
14+
"ajv": "8.18.0",
15+
"ajv-formats": "3.0.1"
1216
}
1317
}

schemas/plugin.schema.json

Lines changed: 134 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,134 @@
1+
{
2+
"$schema": "http://json-schema.org/draft-07/schema#",
3+
"$id": "https://cursor.com/schemas/cursor-plugin/plugin.json",
4+
"title": "Cursor Plugin Manifest",
5+
"description": "Schema for .cursor-plugin/plugin.json — defines a single Cursor plugin's metadata, components, and configuration.",
6+
"type": "object",
7+
"required": ["name"],
8+
"additionalProperties": false,
9+
"properties": {
10+
"name": {
11+
"type": "string",
12+
"minLength": 1,
13+
"pattern": "^[a-z0-9]([a-z0-9.-]*[a-z0-9])?$",
14+
"description": "Unique plugin identifier in kebab-case (lowercase alphanumeric with hyphens and periods)."
15+
},
16+
"displayName": {
17+
"type": "string",
18+
"description": "Human-readable display name for the plugin."
19+
},
20+
"description": {
21+
"type": "string",
22+
"description": "Short description of what the plugin does."
23+
},
24+
"version": {
25+
"type": "string",
26+
"description": "Semantic version of the plugin (e.g. \"1.2.3\")."
27+
},
28+
"author": {
29+
"$ref": "#/$defs/author",
30+
"description": "The plugin author."
31+
},
32+
"publisher": {
33+
"type": "string",
34+
"minLength": 1,
35+
"description": "Publisher or organisation name."
36+
},
37+
"homepage": {
38+
"type": "string",
39+
"format": "uri",
40+
"description": "URL to the plugin's homepage."
41+
},
42+
"repository": {
43+
"type": "string",
44+
"format": "uri",
45+
"description": "URL to the plugin's source code repository."
46+
},
47+
"license": {
48+
"type": "string",
49+
"description": "SPDX license identifier (e.g. \"MIT\", \"Apache-2.0\")."
50+
},
51+
"logo": {
52+
"type": "string",
53+
"description": "Path to a logo image (relative to the plugin root) or an absolute URL."
54+
},
55+
"keywords": {
56+
"type": "array",
57+
"items": { "type": "string" },
58+
"description": "Keywords for discovery and search."
59+
},
60+
"category": {
61+
"type": "string",
62+
"description": "Plugin category for marketplace classification."
63+
},
64+
"tags": {
65+
"type": "array",
66+
"items": { "type": "string" },
67+
"description": "Tags for filtering and discovery."
68+
},
69+
"commands": {
70+
"$ref": "#/$defs/stringOrStringArray",
71+
"description": "Glob pattern(s) or path(s) to command files."
72+
},
73+
"agents": {
74+
"$ref": "#/$defs/stringOrStringArray",
75+
"description": "Glob pattern(s) or path(s) to agent definition files."
76+
},
77+
"skills": {
78+
"$ref": "#/$defs/stringOrStringArray",
79+
"description": "Glob pattern(s) or path(s) to skill files."
80+
},
81+
"rules": {
82+
"$ref": "#/$defs/stringOrStringArray",
83+
"description": "Glob pattern(s) or path(s) to rule files."
84+
},
85+
"hooks": {
86+
"oneOf": [{ "type": "string" }, { "type": "object" }],
87+
"description": "Path to a hooks configuration file, or an inline hooks object."
88+
},
89+
"mcpServers": {
90+
"$ref": "#/$defs/mcpServers",
91+
"description": "MCP server configuration — a path, an inline config object, or an array of either."
92+
}
93+
},
94+
"$defs": {
95+
"author": {
96+
"type": "object",
97+
"required": ["name"],
98+
"additionalProperties": false,
99+
"properties": {
100+
"name": {
101+
"type": "string",
102+
"minLength": 1,
103+
"description": "Author name."
104+
},
105+
"email": {
106+
"type": "string",
107+
"format": "email",
108+
"description": "Author email address."
109+
}
110+
}
111+
},
112+
"stringOrStringArray": {
113+
"oneOf": [
114+
{ "type": "string" },
115+
{
116+
"type": "array",
117+
"items": { "type": "string" }
118+
}
119+
]
120+
},
121+
"mcpServers": {
122+
"oneOf": [
123+
{ "type": "string" },
124+
{ "type": "object" },
125+
{
126+
"type": "array",
127+
"items": {
128+
"oneOf": [{ "type": "string" }, { "type": "object" }]
129+
}
130+
}
131+
]
132+
}
133+
}
134+
}

scripts/validate-plugin.mjs

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,13 @@
11
#!/usr/bin/env node
2+
import Ajv from "ajv";
3+
import addFormats from "ajv-formats";
24
import fs from "node:fs";
35
import path from "node:path";
46

57
const root = process.cwd();
68
const expectedApiKeyInterpolation = "$" + "{LEADMAGIC_API_KEY}";
9+
const expectedSubmissionLogoUrl =
10+
"https://raw.githubusercontent.com/LeadMagic/leadmagic-cursor-plugin/main/assets/logo.svg";
711

812
function readJson(relPath) {
913
return JSON.parse(fs.readFileSync(path.join(root, relPath), "utf8"));
@@ -17,17 +21,42 @@ function assert(condition, message) {
1721
if (!condition) throw new Error(message);
1822
}
1923

24+
function formatAjvErrors(errors) {
25+
if (!errors?.length) {
26+
return "unknown schema validation error";
27+
}
28+
29+
return errors
30+
.map((error) => {
31+
if (error.keyword === "additionalProperties") {
32+
return `${error.instancePath || "/"}: ${error.message} (${error.params.additionalProperty})`;
33+
}
34+
35+
return `${error.instancePath || "/"}: ${error.message}`;
36+
})
37+
.join("; ");
38+
}
39+
2040
function frontmatter(text) {
2141
const match = text.match(/^---\n([\s\S]*?)\n---/);
2242
return match ? match[1] : null;
2343
}
2444

2545
try {
46+
const pluginSchema = readJson("schemas/plugin.schema.json");
47+
const ajv = new Ajv({ allErrors: true });
48+
addFormats(ajv);
49+
const validatePlugin = ajv.compile(pluginSchema);
50+
2651
assert(
2752
exists(".cursor-plugin/plugin.json"),
2853
"Missing .cursor-plugin/plugin.json",
2954
);
3055
const plugin = readJson(".cursor-plugin/plugin.json");
56+
assert(
57+
validatePlugin(plugin),
58+
`plugin.json must satisfy Cursor's official plugin schema: ${formatAjvErrors(validatePlugin.errors)}`,
59+
);
3160

3261
assert(
3362
/^[a-z0-9-]+$/.test(plugin.name),
@@ -61,6 +90,10 @@ try {
6190
plugin.rules === "./rules/",
6291
"Plugin must expose the rules directory with an explicit relative path",
6392
);
93+
assert(
94+
exists("schemas/plugin.schema.json"),
95+
"Missing vendored Cursor plugin schema at schemas/plugin.schema.json",
96+
);
6497
assert(exists(plugin.logo), `Missing logo file: ${plugin.logo}`);
6598

6699
assert(
@@ -156,6 +189,10 @@ try {
156189
submission.includes("hosted MCP surface"),
157190
"SUBMISSION.md description must mention the hosted MCP surface",
158191
);
192+
assert(
193+
submission.includes(expectedSubmissionLogoUrl),
194+
"SUBMISSION.md must use the repo-hosted canonical logo URL",
195+
);
159196
assert(
160197
plugin.repository ===
161198
"https://github.com/LeadMagic/leadmagic-cursor-plugin",

0 commit comments

Comments
 (0)