ai-supply-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.
Files changed (3) hide show
  1. package/README.md +5 -5
  2. package/package.json +26 -6
  3. package/server.mjs +28 -26
package/README.md CHANGED
@@ -1,10 +1,10 @@
1
1
  # ai-supply-mcp
2
2
 
3
- MCP server for **[ai-supply.store](https://ai-supply.store)** — the security-scanned marketplace for AI capabilities. Connect it to any MCP client (Claude Code, Claude Desktop, VS Code / GitHub Copilot, Cursor) and your agent can **search, install, download, publish, version, and review** capabilities natively — full parity with the website.
3
+ MCP server for **[ai-supply.store](https://ai-supply.store)** — the free, security-vetted registry of AI capabilities. Every capability is downloaded, scanned, and graded **0–100 (A–D)** for security before it's listed; risky ones are hidden by default. Connect it to any MCP client (Claude Code, Claude Desktop, VS Code / GitHub Copilot, Cursor) and your agent can **search, install, download, publish, version, and review** capabilities natively — full parity with the website, and every search result carries its security score.
4
4
 
5
5
  ## 1. Get an API key
6
6
 
7
- Create one at **https://ai-supply.store/dashboard/api-keys** and pick the scopes the agent needs (`read`, `install`, `purchase`, `publish`, `review`, `manage`, `account`). The server mints a short-lived, revocable agent **session** from your key on startup, so the long-lived key isn't sent on every request.
7
+ Create one at **https://ai-supply.store/dashboard/api-keys** and pick the scopes the agent needs (`read`, `install`, `publish`, `review`, `manage`, `account`). The `read` scope alone is enough to browse the vetted catalog. The server mints a short-lived, revocable agent **session** from your key on startup, so the long-lived key isn't sent on every request.
8
8
 
9
9
  ## 2. Add it to your client
10
10
 
@@ -32,11 +32,11 @@ claude mcp add ai-supply --env AIM_API_KEY=aim_your_key_here -- npx -y ai-supply
32
32
 
33
33
  > VS Code / Copilot also discover this server from the MCP Registry — search `@mcp ai-supply` in the Extensions view.
34
34
 
35
- ## Tools (19)
35
+ ## Tools (17)
36
36
 
37
- `whoami`, `list_categories`, `list_kinds`, `search_listings`, `get_listing`, `install_listing`, `purchase_listing`, `download_listing`, `review_listing`, `upload_artifact`, `publish_listing`, `update_listing`, `delete_listing`, `add_version`, `my_listings`, `list_community`, `post_community`, `accept_agreements`, `my_revenue`.
37
+ `whoami`, `list_categories`, `list_kinds`, `search_listings`, `get_listing`, `install_listing`, `download_listing`, `review_listing`, `upload_artifact`, `publish_listing`, `update_listing`, `delete_listing`, `add_version`, `my_listings`, `list_community`, `post_community`, `accept_agreements`.
38
38
 
39
- Each tool calls the corresponding `/api/v1` endpoint and is gated by the credential's scopes (and spend cap for purchases). Every capability on ai-supply is security-scanned, scored, and graded before it's published.
39
+ Each tool calls the corresponding `/api/v1` endpoint and is gated by the credential's scopes. Every capability on ai-supply is security-scanned and graded (0–100 score, A–D grade) before it's listed — `search_listings` supports `sort: "security"` to rank the most-secure first, `get_listing` returns the full scan findings, and quarantined (critical-finding) listings are hidden by default. The whole catalog is **free**. See <https://ai-supply.store/security> for the vetting methodology.
40
40
 
41
41
  ## Local development
42
42
 
package/package.json CHANGED
@@ -1,16 +1,36 @@
1
1
  {
2
2
  "name": "ai-supply-mcp",
3
- "version": "1.0.0",
3
+ "version": "1.1.0",
4
4
  "type": "module",
5
- "bin": { "ai-supply-mcp": "./server.mjs" },
5
+ "bin": {
6
+ "ai-supply-mcp": "./server.mjs"
7
+ },
6
8
  "description": "MCP server for ai-supply.store — search, install, download, publish and review security-scanned AI capabilities from any MCP client (Claude, VS Code/Copilot, Cursor).",
7
9
  "mcpName": "io.github.ai-supply-store/ai-supply",
8
10
  "homepage": "https://ai-supply.store",
9
- "repository": { "type": "git", "url": "git+https://github.com/ai-supply-store/ai-supply-plugin.git", "directory": "mcp" },
11
+ "repository": {
12
+ "type": "git",
13
+ "url": "git+https://github.com/ai-supply-store/ai-supply-plugin.git",
14
+ "directory": "mcp"
15
+ },
10
16
  "license": "MIT",
11
- "keywords": ["mcp", "modelcontextprotocol", "ai-supply", "marketplace", "ai-agents", "claude", "copilot"],
12
- "files": ["server.mjs", "lib.mjs", "README.md"],
13
- "engines": { "node": ">=18" },
17
+ "keywords": [
18
+ "mcp",
19
+ "modelcontextprotocol",
20
+ "ai-supply",
21
+ "marketplace",
22
+ "ai-agents",
23
+ "claude",
24
+ "copilot"
25
+ ],
26
+ "files": [
27
+ "server.mjs",
28
+ "lib.mjs",
29
+ "README.md"
30
+ ],
31
+ "engines": {
32
+ "node": ">=18"
33
+ },
14
34
  "dependencies": {
15
35
  "@modelcontextprotocol/sdk": "^1.29.0",
16
36
  "zod": "^3.24.1"
package/server.mjs CHANGED
@@ -2,9 +2,11 @@
2
2
  /**
3
3
  * ai-supply MCP server.
4
4
  *
5
- * Exposes the marketplace Agent API as MCP tools so any MCP-speaking agent
6
- * (Claude, etc.) can discover, install, purchase, download, publish, update and
7
- * review capabilities — everything a human can do.
5
+ * Exposes the ai-supply Agent API as MCP tools so any MCP-speaking agent
6
+ * (Claude, etc.) can discover, install, download, publish, update and review
7
+ * capabilities from a free, security-vetted registry — everything a human can do.
8
+ * Every listing is security-scanned and graded (0–100 score, A–D grade); risky
9
+ * (quarantined) ones are hidden by default and each result carries its score.
8
10
  *
9
11
  * Auth: set AIM_API_KEY (create one at /dashboard/api-keys). The server mints a
10
12
  * short-lived agent SESSION from your key on startup and uses it for calls, so
@@ -18,10 +20,10 @@ import { apiUrl, authHeaders, qs } from "./lib.mjs";
18
20
 
19
21
  const BASE = process.env.AIM_BASE_URL || "https://ai-supply.store";
20
22
  const API_KEY = process.env.AIM_API_KEY;
21
- if (!API_KEY) {
22
- console.error("AIM_API_KEY is required. Create one at /dashboard/api-keys.");
23
- process.exit(1);
24
- }
23
+ // Don't exit when the key is missing — start anyway so the client lists the tools,
24
+ // and return a clear setup hint from each call (silent exit = confusing "0 tools").
25
+ const NO_KEY_MSG =
26
+ "No API key configured. Set the AIM_API_KEY environment variable for the ai-supply MCP server and reload — create one (the 'read' scope is enough to browse) at https://ai-supply.store/dashboard/api-keys";
25
27
 
26
28
  let TOKEN = API_KEY; // falls back to the raw key if session minting fails
27
29
 
@@ -42,6 +44,7 @@ async function mintSession() {
42
44
  }
43
45
 
44
46
  async function call(method, path, body) {
47
+ if (!API_KEY) return { ok: false, status: 401, data: { error: NO_KEY_MSG } };
45
48
  const res = await fetch(apiUrl(BASE, path), {
46
49
  method,
47
50
  headers: authHeaders(TOKEN, body !== undefined),
@@ -54,6 +57,13 @@ async function call(method, path, body) {
54
57
  } catch {
55
58
  data = { raw: text };
56
59
  }
60
+ if (res.status === 401) {
61
+ data = {
62
+ error:
63
+ "ai-supply rejected the API key (401). Check AIM_API_KEY or create a fresh one at https://ai-supply.store/dashboard/api-keys",
64
+ detail: data,
65
+ };
66
+ }
57
67
  return { ok: res.ok, status: res.status, data };
58
68
  }
59
69
 
@@ -64,7 +74,7 @@ function result(r) {
64
74
  };
65
75
  }
66
76
 
67
- const server = new McpServer({ name: "ai-supply", version: "1.0.0" });
77
+ const server = new McpServer({ name: "ai-supply", version: "1.1.0" });
68
78
 
69
79
  const reg = (name, description, shape, handler) =>
70
80
  server.registerTool(name, { description, inputSchema: shape }, handler);
@@ -76,34 +86,30 @@ reg("whoami", "Identity, scopes and agreements of the authenticated agent.", {},
76
86
  reg("list_categories", "List categories and subcategories.", {}, async () =>
77
87
  result(await call("GET", "/api/v1/categories")),
78
88
  );
79
- reg("list_kinds", "List capability types (kinds) and pricing models.", {}, async () =>
89
+ reg("list_kinds", "List capability types (kinds).", {}, async () =>
80
90
  result(await call("GET", "/api/v1/kinds")),
81
91
  );
82
92
  reg(
83
93
  "search_listings",
84
- "Search the catalog. Filters: q, category, subcategory, kind, price(free|paid), sort(popular|rating|new), limit.",
94
+ "Search the security-vetted catalog. Filters: q, category, subcategory, kind, sort(popular|rating|new|security), limit. Every result carries a security score (0–100) + grade (A–D); risky (quarantined) listings are hidden by default. All listings are free.",
85
95
  {
86
96
  q: z.string().optional(),
87
97
  category: z.string().optional(),
88
98
  subcategory: z.string().optional(),
89
99
  kind: z.string().optional(),
90
- price: z.enum(["free", "paid"]).optional(),
91
- sort: z.enum(["popular", "rating", "new"]).optional(),
100
+ sort: z.enum(["popular", "rating", "new", "security"]).optional(),
92
101
  limit: z.number().int().min(1).max(100).optional(),
93
102
  },
94
103
  async (a) => result(await call("GET", "/api/v1/listings" + qs(a))),
95
104
  );
96
- reg("get_listing", "Get a listing's detail by slug.", { slug: z.string() }, async ({ slug }) =>
105
+ reg("get_listing", "Get a listing's full detail by slug — including its security score, grade, level and scan findings.", { slug: z.string() }, async ({ slug }) =>
97
106
  result(await call("GET", `/api/v1/listings/${slug}`)),
98
107
  );
99
108
 
100
109
  // ---- Consume ----
101
- reg("install_listing", "Install a free listing (records ownership).", { slug: z.string() }, async ({ slug }) =>
110
+ reg("install_listing", "Install a listing (free; records ownership). Downloads are gated on a passing security scan.", { slug: z.string() }, async ({ slug }) =>
102
111
  result(await call("POST", `/api/v1/listings/${slug}/install`)),
103
112
  );
104
- reg("purchase_listing", "Purchase a paid listing (needs 'purchase' scope; respects spend cap).", { slug: z.string() }, async ({ slug }) =>
105
- result(await call("POST", `/api/v1/listings/${slug}/purchase`)),
106
- );
107
113
  reg("download_listing", "Fetch the latest version artifact ref for an owned listing.", { slug: z.string() }, async ({ slug }) =>
108
114
  result(await call("GET", `/api/v1/listings/${slug}/download`)),
109
115
  );
@@ -131,8 +137,6 @@ reg(
131
137
  subcategorySlug: z.string().optional(),
132
138
  shortDesc: z.string(),
133
139
  longDescriptionMd: z.string().optional(),
134
- pricingModel: z.enum(["FREE", "ONE_TIME", "PER_CALL", "SUBSCRIPTION"]).optional(),
135
- priceAmount: z.number().int().optional(),
136
140
  version: z.string().optional(),
137
141
  versionContent: z.string().optional(),
138
142
  filePath: z.string().optional(),
@@ -149,8 +153,6 @@ reg(
149
153
  name: z.string().optional(),
150
154
  shortDesc: z.string().optional(),
151
155
  longDescriptionMd: z.string().optional(),
152
- pricingModel: z.enum(["FREE", "ONE_TIME", "PER_CALL", "SUBSCRIPTION"]).optional(),
153
- priceAmount: z.number().int().optional(),
154
156
  status: z.enum(["DRAFT", "PUBLISHED", "SUSPENDED"]).optional(),
155
157
  },
156
158
  async ({ slug, ...patch }) => result(await call("PATCH", `/api/v1/listings/${slug}`, patch)),
@@ -186,10 +188,10 @@ reg(
186
188
  { kind: z.enum(["terms", "publisher", "both"]).optional() },
187
189
  async (a) => result(await call("POST", "/api/v1/me/accept", a)),
188
190
  );
189
- reg("my_revenue", "Aggregate (mock) revenue for your listings.", {}, async () =>
190
- result(await call("GET", "/api/v1/me/revenue")),
191
- );
192
191
 
193
- await mintSession();
192
+ if (API_KEY) await mintSession();
194
193
  await server.connect(new StdioServerTransport());
195
- console.error(`ai-supply MCP server connected (base: ${BASE})`);
194
+ console.error(
195
+ `ai-supply MCP server connected (base: ${BASE})` +
196
+ (API_KEY ? "" : " — WARNING: AIM_API_KEY not set; tools will return a setup hint until you configure it."),
197
+ );