storkai 1.0.0 → 1.0.1

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 (2) hide show
  1. package/bin/storkai.js +48 -12
  2. package/package.json +1 -4
package/bin/storkai.js CHANGED
@@ -6,16 +6,39 @@
6
6
  * Install once: npx storkai
7
7
  *
8
8
  * https://www.stork.ai/mcp
9
+ *
10
+ * Zero dependencies — uses only Node.js built-in fetch().
9
11
  */
10
12
 
11
13
  import process from "node:process";
12
- import { ConvexHttpClient } from "convex/browser";
13
14
 
14
15
  const SERVER_NAME = "storkai";
15
- const SERVER_VERSION = "1.0.0";
16
- const CONVEX_URL = "https://expert-egret-407.convex.cloud";
16
+ const SERVER_VERSION = "1.0.1";
17
+ const CONVEX_URL = process.env.STORK_CONVEX_URL || "https://expert-egret-407.convex.cloud";
18
+
19
+ async function convexQuery(fnPath, args) {
20
+ const res = await fetch(`${CONVEX_URL}/api/query`, {
21
+ method: "POST",
22
+ headers: { "Content-Type": "application/json" },
23
+ body: JSON.stringify({ path: fnPath, args: args ?? {}, format: "json" }),
24
+ });
25
+ if (!res.ok) throw new Error(`Convex query failed: ${res.status}`);
26
+ const data = await res.json();
27
+ if (data.status === "error") throw new Error(data.errorMessage || "Query error");
28
+ return data.value;
29
+ }
17
30
 
18
- const client = new ConvexHttpClient(process.env.STORK_CONVEX_URL || CONVEX_URL);
31
+ async function convexAction(fnPath, args) {
32
+ const res = await fetch(`${CONVEX_URL}/api/action`, {
33
+ method: "POST",
34
+ headers: { "Content-Type": "application/json" },
35
+ body: JSON.stringify({ path: fnPath, args: args ?? {}, format: "json" }),
36
+ });
37
+ if (!res.ok) throw new Error(`Convex action failed: ${res.status}`);
38
+ const data = await res.json();
39
+ if (data.status === "error") throw new Error(data.errorMessage || "Action error");
40
+ return data.value;
41
+ }
19
42
 
20
43
  let stdinBuffer = Buffer.alloc(0);
21
44
 
@@ -115,15 +138,15 @@ function fmtCompare(d) {
115
138
 
116
139
  const tools = [
117
140
  { name: "stork_search", description: "Search for MCP servers by natural language. Example: 'manage Jira tickets' or 'query Postgres databases'. Returns top matches with trust scores, tools, and install commands.", inputSchema: { type: "object", required: ["query"], properties: { query: { type: "string", description: "What you need the MCP server to do" }, category: { type: "string", description: "Category filter" }, transport: { type: "string", enum: ["stdio", "sse", "streamable-http"], description: "Transport filter" }, limit: { type: "number", minimum: 1, maximum: 10, description: "Max results (default 3)" } } },
118
- handler: async (a) => { const args = { query: String(a.query || ""), category: a.category || undefined, transport: a.transport || undefined, limit: typeof a.limit === "number" ? a.limit : undefined }; try { return fmtSearch(await client.action("mcpDiscoveryActions:semanticSearchServers", args)); } catch { return fmtSearch(await client.query("mcpDiscovery:searchServers", args)); } } },
141
+ handler: async (a) => { const args = { query: String(a.query || ""), category: a.category || undefined, transport: a.transport || undefined, limit: typeof a.limit === "number" ? a.limit : undefined }; try { return fmtSearch(await convexAction("mcpDiscoveryActions:semanticSearchServers", args)); } catch { return fmtSearch(await convexQuery("mcpDiscovery:searchServers", args)); } } },
119
142
  { name: "stork_server_details", description: "Get full details about an MCP server: tools, auth, trust scores, health, and more. Use the slug from search results.", inputSchema: { type: "object", required: ["slug"], properties: { slug: { type: "string", description: "Server slug" } } },
120
- handler: async (a) => fmtDetails(await client.query("mcpDiscovery:getServerDetails", { slug: String(a.slug) })) },
143
+ handler: async (a) => fmtDetails(await convexQuery("mcpDiscovery:getServerDetails", { slug: String(a.slug) })) },
121
144
  { name: "stork_get_install_config", description: "Get ready-to-paste JSON config for installing an MCP server in your IDE. Supports cursor, claude-desktop, claude-code, vscode, and zed.", inputSchema: { type: "object", required: ["slug", "client"], properties: { slug: { type: "string", description: "Server slug" }, client: { type: "string", enum: ["cursor", "claude-desktop", "claude-code", "vscode", "zed"], description: "Target IDE" } } },
122
- handler: async (a) => fmtConfig(await client.query("mcpDiscovery:getInstallConfig", { slug: String(a.slug), client: String(a.client) })) },
145
+ handler: async (a) => fmtConfig(await convexQuery("mcpDiscovery:getInstallConfig", { slug: String(a.slug), client: String(a.client) })) },
123
146
  { name: "stork_compare", description: "Compare 2-5 MCP servers side by side on tools, trust, transport, auth, and more.", inputSchema: { type: "object", required: ["slugs"], properties: { slugs: { type: "array", items: { type: "string" }, minItems: 2, maxItems: 5, description: "Server slugs to compare" } } },
124
- handler: async (a) => fmtCompare(await client.query("mcpDiscovery:compareServers", { slugs: Array.isArray(a.slugs) ? a.slugs.map(String) : [] })) },
147
+ handler: async (a) => fmtCompare(await convexQuery("mcpDiscovery:compareServers", { slugs: Array.isArray(a.slugs) ? a.slugs.map(String) : [] })) },
125
148
  { name: "stork_list_filters", description: "List available categories and hosting filters with server counts.", inputSchema: { type: "object", properties: {} },
126
- handler: async () => { const r = await client.query("mcpServers:listServerFilters", {}); const l = ["# Available Filters\n"]; if (r?.categories?.length) { l.push("## Categories"); for (const c of r.categories) l.push(`- ${c.id} (${c.count})`); } if (r?.hosting?.length) { l.push("\n## Hosting"); for (const h of r.hosting) l.push(`- ${h.id} (${h.count})`); } return l.join("\n"); } },
149
+ handler: async () => { const r = await convexQuery("mcpServers:listServerFilters", {}); const l = ["# Available Filters\n"]; if (r?.categories?.length) { l.push("## Categories"); for (const c of r.categories) l.push(`- ${c.id} (${c.count})`); } if (r?.hosting?.length) { l.push("\n## Hosting"); for (const h of r.hosting) l.push(`- ${h.id} (${h.count})`); } return l.join("\n"); } },
127
150
  { name: "stork_submit", description: "Submit a new MCP server to Stork. Provide a GitHub repo URL or npm package name.", inputSchema: { type: "object", required: ["url"], properties: { url: { type: "string", description: "GitHub repo URL or npm package" }, name: { type: "string", description: "Display name" }, description: { type: "string", description: "What the server does" } } },
128
151
  handler: async (a) => `Submission received for: ${a.url}\n\nTo complete registration, visit: https://www.stork.ai/mcp/submit\nYour server will be auto-enriched with metadata, tools, and trust signals.` },
129
152
  ];
@@ -149,8 +172,10 @@ async function handle(msg) {
149
172
  return rpcError(id, -32601, `Method not found: ${method}`);
150
173
  }
151
174
 
152
- process.stdin.on("data", async (chunk) => {
153
- stdinBuffer = Buffer.concat([stdinBuffer, chunk]);
175
+ let pendingRequests = 0;
176
+ let stdinEnded = false;
177
+
178
+ async function processBuffer() {
154
179
  while (true) {
155
180
  let parsed;
156
181
  try { parsed = parseOneMessage(stdinBuffer); } catch (err) {
@@ -166,9 +191,20 @@ process.stdin.on("data", async (chunk) => {
166
191
  continue;
167
192
  }
168
193
  if (!("id" in msg)) { try { await handle(msg); } catch {} continue; }
194
+ pendingRequests++;
169
195
  try { const r = await handle(msg); if (r) writeMessage(r); }
170
196
  catch (err) { writeMessage(rpcError(msg.id ?? null, -32603, "Internal error", err?.message)); }
197
+ pendingRequests--;
198
+ if (stdinEnded && pendingRequests === 0) process.exit(0);
171
199
  }
200
+ }
201
+
202
+ process.stdin.on("data", (chunk) => {
203
+ stdinBuffer = Buffer.concat([stdinBuffer, chunk]);
204
+ processBuffer();
172
205
  });
173
206
 
174
- process.stdin.on("end", () => process.exit(0));
207
+ process.stdin.on("end", () => {
208
+ stdinEnded = true;
209
+ if (pendingRequests === 0) process.exit(0);
210
+ });
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "storkai",
3
- "version": "1.0.0",
3
+ "version": "1.0.1",
4
4
  "description": "The MCP server for MCP servers. Search, discover, and configure MCP servers from inside your IDE.",
5
5
  "type": "module",
6
6
  "bin": {
@@ -30,9 +30,6 @@
30
30
  "type": "git",
31
31
  "url": "https://github.com/stork-ai/storkai"
32
32
  },
33
- "dependencies": {
34
- "convex": "^1.31.2"
35
- },
36
33
  "engines": {
37
34
  "node": ">=18.0.0"
38
35
  }