mcpstore-gateway 1.0.0 → 1.2.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/dist/index.d.ts CHANGED
@@ -1,11 +1,18 @@
1
1
  #!/usr/bin/env node
2
2
  /**
3
- * MCP Store Gateway
3
+ * MCP Store Gateway v1.2.0
4
4
  *
5
5
  * A single MCP server that gives Claude Code access to ALL your installed MCPs
6
6
  * from mcpclaudecode.com. Install MCPs on the website, they appear here instantly.
7
7
  *
8
- * Usage:
8
+ * Features:
9
+ * - Hosted MCPs: tools proxied through our backend (e.g. AI Brain)
10
+ * - External MCPs: auto-configured in ~/.mcp.json (e.g. GitHub, Playwright)
11
+ *
12
+ * Setup (one command, that's it):
13
+ * npx mcpstore-gateway --setup YOUR_API_KEY
14
+ *
15
+ * Runtime (called automatically by Claude Code):
9
16
  * npx mcpstore-gateway --api-key YOUR_API_KEY
10
17
  */
11
18
  export {};
package/dist/index.js CHANGED
@@ -1,41 +1,150 @@
1
1
  #!/usr/bin/env node
2
2
  /**
3
- * MCP Store Gateway
3
+ * MCP Store Gateway v1.2.0
4
4
  *
5
5
  * A single MCP server that gives Claude Code access to ALL your installed MCPs
6
6
  * from mcpclaudecode.com. Install MCPs on the website, they appear here instantly.
7
7
  *
8
- * Usage:
8
+ * Features:
9
+ * - Hosted MCPs: tools proxied through our backend (e.g. AI Brain)
10
+ * - External MCPs: auto-configured in ~/.mcp.json (e.g. GitHub, Playwright)
11
+ *
12
+ * Setup (one command, that's it):
13
+ * npx mcpstore-gateway --setup YOUR_API_KEY
14
+ *
15
+ * Runtime (called automatically by Claude Code):
9
16
  * npx mcpstore-gateway --api-key YOUR_API_KEY
10
17
  */
11
18
  import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
12
19
  import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
13
- // ---------------------------------------------------------------------------
14
- // Config
15
- // ---------------------------------------------------------------------------
20
+ import * as fs from "node:fs";
21
+ import * as path from "node:path";
22
+ import * as os from "node:os";
16
23
  const GATEWAY_URL = process.env.MCPSTORE_GATEWAY_URL ||
17
24
  "https://rshsqjofouqyhzvzezos.supabase.co/functions/v1";
18
- function getApiKey() {
19
- // --api-key flag
20
- const flagIdx = process.argv.indexOf("--api-key");
21
- if (flagIdx !== -1 && process.argv[flagIdx + 1]) {
22
- return process.argv[flagIdx + 1];
25
+ // Prefix for auto-managed MCP entries in .mcp.json
26
+ const MANAGED_PREFIX = "mcpstore-";
27
+ async function syncExternalMcps(apiKey) {
28
+ try {
29
+ // 1. Fetch installed external MCPs from the API
30
+ const res = await fetch(`${GATEWAY_URL}/gateway-sync`, {
31
+ headers: {
32
+ Authorization: `Bearer ${apiKey}`,
33
+ "Content-Type": "application/json",
34
+ },
35
+ });
36
+ if (!res.ok)
37
+ return; // Silently fail — sync is best-effort
38
+ const data = (await res.json());
39
+ const installedSlugs = new Set(data.external_mcps.map((m) => m.slug));
40
+ // 2. Read current ~/.mcp.json
41
+ const mcpJsonPath = path.join(os.homedir(), ".mcp.json");
42
+ let config = {};
43
+ if (fs.existsSync(mcpJsonPath)) {
44
+ try {
45
+ config = JSON.parse(fs.readFileSync(mcpJsonPath, "utf-8"));
46
+ }
47
+ catch {
48
+ return; // Don't mess with a broken config
49
+ }
50
+ }
51
+ if (!config.mcpServers) {
52
+ config.mcpServers = {};
53
+ }
54
+ let changed = false;
55
+ // 3. Add new external MCPs (prefixed with mcpstore-)
56
+ for (const mcp of data.external_mcps) {
57
+ const key = `${MANAGED_PREFIX}${mcp.slug}`;
58
+ if (!config.mcpServers[key]) {
59
+ config.mcpServers[key] = mcp.config;
60
+ changed = true;
61
+ }
62
+ }
63
+ // 4. Remove uninstalled MCPs (only those with our prefix)
64
+ for (const key of Object.keys(config.mcpServers)) {
65
+ if (key.startsWith(MANAGED_PREFIX)) {
66
+ const slug = key.slice(MANAGED_PREFIX.length);
67
+ if (!installedSlugs.has(slug)) {
68
+ delete config.mcpServers[key];
69
+ changed = true;
70
+ }
71
+ }
72
+ }
73
+ // 5. Write back if changed
74
+ if (changed) {
75
+ fs.writeFileSync(mcpJsonPath, JSON.stringify(config, null, 2) + "\n", "utf-8");
76
+ }
23
77
  }
24
- // Environment variable
25
- if (process.env.MCPSTORE_API_KEY) {
26
- return process.env.MCPSTORE_API_KEY;
78
+ catch {
79
+ // Sync is best-effort, never block the server from starting
27
80
  }
28
- console.error("Error: No API key provided.\n" +
29
- "Usage: mcpstore-gateway --api-key YOUR_KEY\n" +
30
- " or: MCPSTORE_API_KEY=YOUR_KEY mcpstore-gateway\n\n" +
31
- "Get your API key at https://www.mcpclaudecode.com/dashboard");
32
- process.exit(1);
33
81
  }
34
- const API_KEY = getApiKey();
35
- async function fetchTools() {
82
+ // ---------------------------------------------------------------------------
83
+ // Setup mode: auto-configure .mcp.json
84
+ // ---------------------------------------------------------------------------
85
+ async function runSetup(apiKey) {
86
+ console.log("");
87
+ console.log(" MCP Store — Configuration automatique");
88
+ console.log(" ======================================");
89
+ console.log("");
90
+ // 1. Validate the API key
91
+ console.log(" [1/3] Verification de la cle API...");
92
+ try {
93
+ const res = await fetch(`${GATEWAY_URL}/gateway-tools`, {
94
+ headers: { Authorization: `Bearer ${apiKey}` },
95
+ });
96
+ if (!res.ok) {
97
+ const body = await res.json().catch(() => ({}));
98
+ console.error(`\n Erreur: ${body.error || "Cle API invalide"}`);
99
+ console.error(" Verifiez votre cle sur https://www.mcpclaudecode.com/dashboard\n");
100
+ process.exit(1);
101
+ }
102
+ const data = (await res.json());
103
+ console.log(` OK — ${data.count || 0} outil(s) disponible(s)`);
104
+ }
105
+ catch {
106
+ console.error("\n Erreur: impossible de contacter MCP Store.");
107
+ console.error(" Verifiez votre connexion internet.\n");
108
+ process.exit(1);
109
+ }
110
+ // 2. Find or create .mcp.json
111
+ console.log(" [2/3] Configuration de Claude Code...");
112
+ const mcpJsonPath = path.join(os.homedir(), ".mcp.json");
113
+ let config = {};
114
+ if (fs.existsSync(mcpJsonPath)) {
115
+ try {
116
+ config = JSON.parse(fs.readFileSync(mcpJsonPath, "utf-8"));
117
+ }
118
+ catch {
119
+ // File exists but isn't valid JSON — we'll create a fresh one
120
+ }
121
+ }
122
+ if (!config.mcpServers) {
123
+ config.mcpServers = {};
124
+ }
125
+ config.mcpServers.mcpstore = {
126
+ command: "npx",
127
+ args: ["-y", "mcpstore-gateway", "--api-key", apiKey],
128
+ };
129
+ fs.writeFileSync(mcpJsonPath, JSON.stringify(config, null, 2) + "\n", "utf-8");
130
+ console.log(` OK — ${mcpJsonPath}`);
131
+ // 3. Done!
132
+ console.log(" [3/3] Termine !");
133
+ console.log("");
134
+ console.log(" +--------------------------------------------------+");
135
+ console.log(" | MCP Store est configure ! |");
136
+ console.log(" | |");
137
+ console.log(" | Redemarrez Claude Code pour activer vos MCPs. |");
138
+ console.log(" | |");
139
+ console.log(" | Installez des MCPs : |");
140
+ console.log(" | https://www.mcpclaudecode.com/browse |");
141
+ console.log(" +--------------------------------------------------+");
142
+ console.log("");
143
+ }
144
+ async function fetchTools(apiKey) {
36
145
  const res = await fetch(`${GATEWAY_URL}/gateway-tools`, {
37
146
  headers: {
38
- Authorization: `Bearer ${API_KEY}`,
147
+ Authorization: `Bearer ${apiKey}`,
39
148
  "Content-Type": "application/json",
40
149
  },
41
150
  });
@@ -46,11 +155,11 @@ async function fetchTools() {
46
155
  const data = (await res.json());
47
156
  return data.tools || [];
48
157
  }
49
- async function callTool(toolName, args) {
158
+ async function callTool(apiKey, toolName, args) {
50
159
  const res = await fetch(`${GATEWAY_URL}/gateway-call`, {
51
160
  method: "POST",
52
161
  headers: {
53
- Authorization: `Bearer ${API_KEY}`,
162
+ Authorization: `Bearer ${apiKey}`,
54
163
  "Content-Type": "application/json",
55
164
  },
56
165
  body: JSON.stringify({ tool: toolName, arguments: args }),
@@ -62,88 +171,60 @@ async function callTool(toolName, args) {
62
171
  const data = (await res.json());
63
172
  return data.result ?? data;
64
173
  }
65
- // ---------------------------------------------------------------------------
66
- // MCP Server
67
- // ---------------------------------------------------------------------------
68
- const server = new McpServer({
69
- name: "MCP Store",
70
- version: "1.0.0",
71
- });
72
- // Cache tools to avoid re-fetching on every call
73
- let toolsCache = null;
74
- let toolsCacheTime = 0;
75
- const CACHE_TTL_MS = 60_000; // 1 min
76
- async function getTools() {
77
- const now = Date.now();
78
- if (toolsCache && now - toolsCacheTime < CACHE_TTL_MS) {
79
- return toolsCache;
80
- }
81
- toolsCache = await fetchTools();
82
- toolsCacheTime = now;
83
- return toolsCache;
84
- }
85
- // Register a dynamic tool handler — we fetch tools from the gateway and
86
- // register them all. MCP SDK requires registering tools at init time, so we
87
- // fetch once at startup, then use the call handler to proxy dynamically.
88
- async function registerTools() {
89
- const tools = await getTools();
90
- if (tools.length === 0) {
91
- // Register a placeholder tool so the server isn't empty
92
- server.tool("mcpstore__info", "No MCPs installed yet. Visit https://www.mcpclaudecode.com/browse to install MCPs.", {}, async () => ({
93
- content: [
94
- {
95
- type: "text",
96
- text: "You have no MCPs installed. Visit https://www.mcpclaudecode.com/browse to browse and install MCPs. They will appear here automatically!",
97
- },
98
- ],
99
- }));
100
- return;
101
- }
102
- for (const tool of tools) {
103
- // Build the input schema shape for the MCP SDK
104
- const shape = {};
105
- const schema = tool.inputSchema;
106
- if (schema?.properties) {
107
- // We pass through the raw JSON Schema — the SDK accepts it
108
- for (const [key, value] of Object.entries(schema.properties)) {
109
- shape[key] = value;
110
- }
174
+ async function runServer(apiKey) {
175
+ // Sync external MCPs to ~/.mcp.json before starting
176
+ await syncExternalMcps(apiKey);
177
+ const server = new McpServer({
178
+ name: "MCP Store",
179
+ version: "1.2.0",
180
+ });
181
+ // Register hosted tools (proxied through our backend)
182
+ try {
183
+ const tools = await fetchTools(apiKey);
184
+ if (tools.length === 0) {
185
+ server.tool("mcpstore__info", "No MCPs installed yet. Visit https://www.mcpclaudecode.com/browse to install MCPs.", {}, async () => ({
186
+ content: [
187
+ {
188
+ type: "text",
189
+ text: "You have no MCPs installed. Visit https://www.mcpclaudecode.com/browse to browse and install MCPs. They will appear here automatically!",
190
+ },
191
+ ],
192
+ }));
111
193
  }
112
- server.tool(tool.name, tool.description,
113
- // Pass the raw JSON Schema as-is; the SDK will use it for validation
114
- shape, async (args) => {
115
- try {
116
- const result = await callTool(tool.name, args);
117
- const text = typeof result === "string" ? result : JSON.stringify(result, null, 2);
118
- return {
119
- content: [{ type: "text", text }],
120
- };
121
- }
122
- catch (err) {
123
- return {
124
- content: [
125
- {
126
- type: "text",
127
- text: `Error: ${err.message}`,
128
- },
129
- ],
130
- isError: true,
131
- };
194
+ else {
195
+ for (const tool of tools) {
196
+ const shape = {};
197
+ const schema = tool.inputSchema;
198
+ if (schema?.properties) {
199
+ for (const [key, value] of Object.entries(schema.properties)) {
200
+ shape[key] = value;
201
+ }
202
+ }
203
+ server.tool(tool.name, tool.description, shape, async (args) => {
204
+ try {
205
+ const result = await callTool(apiKey, tool.name, args);
206
+ const text = typeof result === "string"
207
+ ? result
208
+ : JSON.stringify(result, null, 2);
209
+ return { content: [{ type: "text", text }] };
210
+ }
211
+ catch (err) {
212
+ return {
213
+ content: [
214
+ {
215
+ type: "text",
216
+ text: `Error: ${err.message}`,
217
+ },
218
+ ],
219
+ isError: true,
220
+ };
221
+ }
222
+ });
132
223
  }
133
- });
134
- }
135
- }
136
- // ---------------------------------------------------------------------------
137
- // Main
138
- // ---------------------------------------------------------------------------
139
- async function main() {
140
- try {
141
- await registerTools();
224
+ }
142
225
  }
143
226
  catch (err) {
144
227
  console.error("Failed to fetch tools from MCP Store:", err.message);
145
- console.error("Make sure your API key is valid and you have MCPs installed at https://www.mcpclaudecode.com/browse");
146
- // Still start the server with an error tool
147
228
  server.tool("mcpstore__error", "MCP Store connection error", {}, async () => ({
148
229
  content: [
149
230
  {
@@ -157,4 +238,34 @@ async function main() {
157
238
  const transport = new StdioServerTransport();
158
239
  await server.connect(transport);
159
240
  }
241
+ // ---------------------------------------------------------------------------
242
+ // Entry point
243
+ // ---------------------------------------------------------------------------
244
+ async function main() {
245
+ // --setup mode
246
+ const setupIdx = process.argv.indexOf("--setup");
247
+ if (setupIdx !== -1) {
248
+ const key = process.argv[setupIdx + 1];
249
+ if (!key) {
250
+ console.error("Usage: npx mcpstore-gateway --setup YOUR_API_KEY");
251
+ console.error("\nGet your API key at https://www.mcpclaudecode.com/dashboard");
252
+ process.exit(1);
253
+ }
254
+ await runSetup(key);
255
+ process.exit(0);
256
+ }
257
+ // --api-key runtime mode
258
+ const flagIdx = process.argv.indexOf("--api-key");
259
+ const apiKey = (flagIdx !== -1 && process.argv[flagIdx + 1]) ||
260
+ process.env.MCPSTORE_API_KEY ||
261
+ "";
262
+ if (!apiKey) {
263
+ console.error("Error: No API key provided.\n" +
264
+ "Setup: npx mcpstore-gateway --setup YOUR_KEY\n" +
265
+ "Runtime: npx mcpstore-gateway --api-key YOUR_KEY\n\n" +
266
+ "Get your API key at https://www.mcpclaudecode.com/dashboard");
267
+ process.exit(1);
268
+ }
269
+ await runServer(apiKey);
270
+ }
160
271
  main();
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "mcpstore-gateway",
3
- "version": "1.0.0",
3
+ "version": "1.2.0",
4
4
  "description": "MCP Store Gateway — One MCP server for all your installed MCPs from mcpclaudecode.com",
5
5
  "keywords": ["mcp", "claude", "claude-code", "ai", "gateway", "marketplace"],
6
6
  "license": "MIT",