fodda-mcp 1.3.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 (59) hide show
  1. package/README.md +124 -0
  2. package/dist/index.d.ts +3 -0
  3. package/dist/index.d.ts.map +1 -0
  4. package/dist/index.js +434 -0
  5. package/dist/index.js.map +1 -0
  6. package/dist/scripts/simulate_gemini.d.ts +2 -0
  7. package/dist/scripts/simulate_gemini.d.ts.map +1 -0
  8. package/dist/scripts/simulate_gemini.js +100 -0
  9. package/dist/scripts/simulate_gemini.js.map +1 -0
  10. package/dist/scripts/verify_registry.d.ts +2 -0
  11. package/dist/scripts/verify_registry.d.ts.map +1 -0
  12. package/dist/scripts/verify_registry.js +77 -0
  13. package/dist/scripts/verify_registry.js.map +1 -0
  14. package/dist/src/index.d.ts +2 -0
  15. package/dist/src/index.d.ts.map +1 -0
  16. package/dist/src/index.js +332 -0
  17. package/dist/src/index.js.map +1 -0
  18. package/dist/src/tools.d.ts +12 -0
  19. package/dist/src/tools.d.ts.map +1 -0
  20. package/dist/src/tools.js +104 -0
  21. package/dist/src/tools.js.map +1 -0
  22. package/dist/src/types.d.ts +44 -0
  23. package/dist/src/types.d.ts.map +1 -0
  24. package/dist/src/types.js +2 -0
  25. package/dist/src/types.js.map +1 -0
  26. package/dist/src/verify.d.ts +2 -0
  27. package/dist/src/verify.d.ts.map +1 -0
  28. package/dist/src/verify.js +47 -0
  29. package/dist/src/verify.js.map +1 -0
  30. package/dist/src/verify_hmac.d.ts +2 -0
  31. package/dist/src/verify_hmac.d.ts.map +1 -0
  32. package/dist/src/verify_hmac.js +106 -0
  33. package/dist/src/verify_hmac.js.map +1 -0
  34. package/dist/src/verify_tools_endpoint.d.ts +2 -0
  35. package/dist/src/verify_tools_endpoint.d.ts.map +1 -0
  36. package/dist/src/verify_tools_endpoint.js +40 -0
  37. package/dist/src/verify_tools_endpoint.js.map +1 -0
  38. package/dist/tools.d.ts +12 -0
  39. package/dist/tools.d.ts.map +1 -0
  40. package/dist/tools.js +191 -0
  41. package/dist/tools.js.map +1 -0
  42. package/dist/types.d.ts +44 -0
  43. package/dist/types.d.ts.map +1 -0
  44. package/dist/types.js +2 -0
  45. package/dist/types.js.map +1 -0
  46. package/dist/verify.d.ts +2 -0
  47. package/dist/verify.d.ts.map +1 -0
  48. package/dist/verify.js +47 -0
  49. package/dist/verify.js.map +1 -0
  50. package/dist/verify_hmac.d.ts +2 -0
  51. package/dist/verify_hmac.d.ts.map +1 -0
  52. package/dist/verify_hmac.js +106 -0
  53. package/dist/verify_hmac.js.map +1 -0
  54. package/dist/verify_tools_endpoint.d.ts +2 -0
  55. package/dist/verify_tools_endpoint.d.ts.map +1 -0
  56. package/dist/verify_tools_endpoint.js +39 -0
  57. package/dist/verify_tools_endpoint.js.map +1 -0
  58. package/package.json +48 -0
  59. package/server.json +49 -0
package/README.md ADDED
@@ -0,0 +1,124 @@
1
+ # Fodda MCP Server
2
+
3
+ **Expert-curated knowledge graphs for AI agents** — PSFK Retail, Beauty, Sports and partner datasets via the Model Context Protocol.
4
+
5
+ [![MCP Registry](https://img.shields.io/badge/MCP_Registry-ai.fodda%2Fmcp--server-blue)](https://registry.modelcontextprotocol.io)
6
+ [![Version](https://img.shields.io/badge/version-1.3.0-green)](./CHANGELOG.md)
7
+
8
+ ---
9
+
10
+ ## Quick Start
11
+
12
+ ### Claude Code
13
+
14
+ ```bash
15
+ claude mcp add --transport sse fodda https://mcp.fodda.ai/sse \
16
+ --header "Authorization: Bearer YOUR_API_KEY"
17
+ ```
18
+
19
+ ### Gemini CLI
20
+
21
+ ```json
22
+ {
23
+ "tools": [{
24
+ "type": "mcp",
25
+ "name": "fodda",
26
+ "url": "https://mcp.fodda.ai/sse",
27
+ "headers": { "Authorization": "Bearer YOUR_API_KEY" }
28
+ }]
29
+ }
30
+ ```
31
+
32
+ ### Generic SSE Client
33
+
34
+ Connect to `https://mcp.fodda.ai/sse` with an `Authorization: Bearer YOUR_API_KEY` header.
35
+
36
+ ---
37
+
38
+ ## Available Tools
39
+
40
+ | Tool | Description | Deterministic |
41
+ |------|-------------|:---:|
42
+ | `search_graph` | Hybrid keyword + semantic search on a knowledge graph | ❌ |
43
+ | `get_neighbors` | Traverse from seed nodes to discover related concepts | ✅ |
44
+ | `get_evidence` | Source signals, articles, and provenance for a node | ✅ |
45
+ | `get_node` | Retrieve metadata for a single node by ID | ✅ |
46
+ | `get_label_values` | Discover valid values for a node label/category | ✅ |
47
+ | `psfk_overview` | Structured macro overview across industries and sectors | ❌ |
48
+
49
+ All tools require `userId` and — except `psfk_overview` — a `graphId`.
50
+
51
+ ### Discovery Endpoints
52
+
53
+ | Endpoint | Description |
54
+ |----------|-------------|
55
+ | `GET /mcp/tools` | Full tool schemas, versions, and capabilities |
56
+ | `GET /health` | Health check (`{ "status": "ok" }`) |
57
+ | `GET /.well-known/mcp.json` | MCP server auto-discovery manifest |
58
+
59
+ ---
60
+
61
+ ## Authentication
62
+
63
+ Pass your Fodda API key as a Bearer token:
64
+
65
+ ```
66
+ Authorization: Bearer fk_live_...
67
+ ```
68
+
69
+ In MCP request `_meta`:
70
+ ```json
71
+ { "_meta": { "authorization": "Bearer fk_live_..." } }
72
+ ```
73
+
74
+ ---
75
+
76
+ ## Configuration
77
+
78
+ | Variable | Description | Default |
79
+ |----------|-------------|---------|
80
+ | `PORT` | SSE server port (omit for stdio mode) | — |
81
+ | `FODDA_API_URL` | Upstream API base URL | `https://api.fodda.ai` |
82
+ | `FODDA_MCP_SECRET` | HMAC signing secret | — |
83
+ | `NODE_ENV` | Environment (`development` / `production`) | `production` |
84
+ | `INTERNAL_TEST_KEYS` | Comma-separated keys for simulation mode | — |
85
+ | `RATE_LIMIT_RPM` | Requests per minute per API key | `60` |
86
+
87
+ ---
88
+
89
+ ## Build & Run
90
+
91
+ ```bash
92
+ npm install
93
+ npm run build
94
+
95
+ # Stdio mode
96
+ npm start
97
+
98
+ # SSE mode
99
+ PORT=8080 npm start
100
+ ```
101
+
102
+ ## Self-Hosting
103
+
104
+ - **Docker**: `docker build -t fodda-mcp . && docker run -p 8080:8080 -e PORT=8080 fodda-mcp`
105
+ - **Cloud Run**: `./deploy_cloud_run.sh`
106
+ - **Kubernetes**: See [`deployment/k8s/`](./deployment/k8s/)
107
+ - **Terraform**: See [`deployment/terraform/`](./deployment/terraform/)
108
+
109
+ ---
110
+
111
+ ## MCP Registry
112
+
113
+ This server is published to the [Official MCP Registry](https://registry.modelcontextprotocol.io) as `ai.fodda/mcp-server`.
114
+
115
+ ```bash
116
+ # Verify listing
117
+ curl "https://registry.modelcontextprotocol.io/v0.1/servers?search=ai.fodda/mcp-server"
118
+ ```
119
+
120
+ ---
121
+
122
+ ## License
123
+
124
+ Proprietary — [fodda.ai](https://www.fodda.ai)
@@ -0,0 +1,3 @@
1
+ #!/usr/bin/env node
2
+ export {};
3
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":""}
package/dist/index.js ADDED
@@ -0,0 +1,434 @@
1
+ #!/usr/bin/env node
2
+ import { Server } from "@modelcontextprotocol/sdk/server/index.js";
3
+ import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
4
+ import crypto from "crypto";
5
+ import { CallToolRequestSchema, ListToolsRequestSchema, } from "@modelcontextprotocol/sdk/types.js";
6
+ import { SSEServerTransport } from "@modelcontextprotocol/sdk/server/sse.js";
7
+ import express from "express";
8
+ import axios from "axios";
9
+ import dotenv from "dotenv";
10
+ import { TOOLS, MCP_SERVER_VERSION } from "./tools.js";
11
+ dotenv.config();
12
+ const API_BASE_URL = process.env.FODDA_API_URL || "https://api.fodda.ai";
13
+ const IS_DEV = process.env.NODE_ENV === "development";
14
+ const DUMMY_API_KEY = "dummy-test-key";
15
+ const DUMMY_USER_ID = "dummy-test-user";
16
+ const server = new Server({
17
+ name: "fodda-mcp",
18
+ version: MCP_SERVER_VERSION,
19
+ }, {
20
+ capabilities: {
21
+ tools: {},
22
+ },
23
+ });
24
+ /**
25
+ * List available tools.
26
+ */
27
+ server.setRequestHandler(ListToolsRequestSchema, async () => {
28
+ return {
29
+ tools: TOOLS,
30
+ };
31
+ });
32
+ /**
33
+ * Handle tool calls.
34
+ */
35
+ server.setRequestHandler(CallToolRequestSchema, async (request) => {
36
+ const { name, arguments: args } = request.params;
37
+ const graphId = args?.graphId;
38
+ let userId = args?.userId;
39
+ // Validate graphId for tools that require it
40
+ if (name !== "psfk_overview" && !graphId) {
41
+ throw new Error("graphId is required for all Fodda tools except psfk_overview.");
42
+ }
43
+ // Extract Bearer Token from _meta
44
+ const authHeader = request.params._meta?.authorization || "";
45
+ let apiKey = typeof authHeader === 'string' && authHeader.startsWith("Bearer ") ? authHeader.substring(7) : null;
46
+ // Strict Enforcement / Dev Mode Fallback
47
+ if (!apiKey) {
48
+ if (IS_DEV) {
49
+ apiKey = DUMMY_API_KEY;
50
+ }
51
+ else {
52
+ return {
53
+ isError: true,
54
+ content: [{ type: "text", text: "Error: No API Key provided. Please include a Bearer token in the 'authorization' field of the MCP request _meta." }],
55
+ };
56
+ }
57
+ }
58
+ if (!userId) {
59
+ if (IS_DEV) {
60
+ userId = DUMMY_USER_ID;
61
+ }
62
+ else {
63
+ return {
64
+ isError: true,
65
+ content: [{ type: "text", text: "Error: No userId provided. This field is required for tracking and billing." }],
66
+ };
67
+ }
68
+ }
69
+ // Enterprise Readiness: Simulated Gemini Tool Invocation Mode
70
+ // strictly enforced production constraints
71
+ const meta = request.params._meta || {};
72
+ const testMode = meta.test_mode;
73
+ if (testMode) {
74
+ // 1. Strict Value Check
75
+ if (testMode !== "gemini_echo") {
76
+ // Silently ignore unknown test modes or throw error?
77
+ // "Reject unknown test modes" -> Throwing error is safer to signal invalid usage
78
+ return {
79
+ isError: true,
80
+ content: [{ type: "text", text: `Error: Invalid test_mode '${testMode}'. Only 'gemini_echo' is supported.` }]
81
+ };
82
+ }
83
+ // 2. Production Guardrails
84
+ // Simulation is ignored (treated as normal unauthorized/error if it falls through, or just explicitly blocked here)
85
+ // unless ENV != production OR API key has role internal_testing.
86
+ // We assume 'apiKey' variable holds the extracted key.
87
+ // Since we can't check roles dynamically without a DB call, we'll use a placeholder logic or ENV var for now.
88
+ const isInternalKey = process.env.INTERNAL_TEST_KEYS?.split(',').includes(apiKey || "");
89
+ const isProduction = process.env.NODE_ENV === "production";
90
+ if (isProduction && !isInternalKey) {
91
+ // In production, matching keys are required to use simulation.
92
+ // If not internal key, we pretend simulation doesn't exist or return error?
93
+ // "Be ignored unless..." -> Proceed to normal execution path (which handles auth/tool call normally)
94
+ // But wait, if we proceed, it tries to execute the tool for real.
95
+ // If the intention is to SAFEGUARD against accidental real execution, we should probably BLOCK if test_mode is present but unauthorized.
96
+ // However, "Be ignored" implies falling back to normal behavior OR just doing nothing.
97
+ // Safest Enterprise approach: If you ASK for test_mode but aren't allowed, FAIL. Don't fall back to real execution which might cost money.
98
+ return {
99
+ isError: true,
100
+ content: [{ type: "text", text: "Error: Simulation mode not permitted in production without internal privileges." }]
101
+ };
102
+ }
103
+ // 3. Structured Logging
104
+ console.error(JSON.stringify({
105
+ event: "mcp.tool_call.simulation",
106
+ simulation_mode: true,
107
+ simulation_type: "gemini_echo",
108
+ tool: name,
109
+ graphId,
110
+ userId
111
+ }));
112
+ // 4. Gemini Echo Response
113
+ return {
114
+ content: [{
115
+ type: "text",
116
+ text: JSON.stringify({
117
+ tool_calls: [{
118
+ name: name,
119
+ arguments: args
120
+ }]
121
+ }, null, 2)
122
+ }]
123
+ };
124
+ }
125
+ const timestamp = Date.now().toString();
126
+ const headers = {
127
+ "X-API-Key": apiKey,
128
+ "X-User-Id": userId,
129
+ "X-Fodda-Timestamp": timestamp,
130
+ "Content-Type": "application/json",
131
+ };
132
+ // Helper to sign payload
133
+ const signRequest = (body) => {
134
+ const secret = process.env.FODDA_MCP_SECRET;
135
+ if (secret) {
136
+ const payload = timestamp + "." + JSON.stringify(body);
137
+ const signature = crypto.createHmac("sha256", secret).update(payload).digest("hex");
138
+ headers["X-Fodda-Signature"] = signature;
139
+ }
140
+ };
141
+ const startTime = Date.now();
142
+ try {
143
+ let response;
144
+ switch (name) {
145
+ case "search_graph": {
146
+ const limit = Math.min(Number(args?.limit) || 25, 50); // Defense in Depth: Cap results
147
+ const body = {
148
+ query: args?.query,
149
+ limit: limit,
150
+ use_semantic: args?.use_semantic !== false,
151
+ };
152
+ signRequest(body);
153
+ response = await axios.post(`${API_BASE_URL}/v1/graphs/${graphId}/search`, body, { headers });
154
+ break;
155
+ }
156
+ case "get_neighbors": {
157
+ const depth = Math.min(Number(args?.depth) || 1, 2); // Defense in Depth: Cap traversal depth
158
+ const limit = Math.min(Number(args?.limit) || 50, 50); // Defense in Depth: Cap results
159
+ const body = {
160
+ seed_node_ids: args?.seed_node_ids,
161
+ relationship_types: args?.relationship_types,
162
+ depth: depth,
163
+ limit: limit,
164
+ };
165
+ signRequest(body);
166
+ response = await axios.post(`${API_BASE_URL}/v1/graphs/${graphId}/neighbors`, body, { headers });
167
+ break;
168
+ }
169
+ case "get_evidence": {
170
+ const top_k = Math.min(Number(args?.top_k) || 5, 10); // Defense in Depth: Cap evidence sources
171
+ const body = {
172
+ for_node_id: args?.for_node_id,
173
+ top_k: top_k,
174
+ };
175
+ signRequest(body);
176
+ response = await axios.post(`${API_BASE_URL}/v1/graphs/${graphId}/evidence`, body, { headers });
177
+ break;
178
+ }
179
+ case "get_node": {
180
+ const getNodePath = `/v1/graphs/${graphId}/nodes/${args?.nodeId}`;
181
+ const getNodeSecret = process.env.FODDA_MCP_SECRET;
182
+ if (getNodeSecret) {
183
+ const payload = timestamp + "." + getNodePath;
184
+ const signature = crypto.createHmac("sha256", getNodeSecret).update(payload).digest("hex");
185
+ headers["X-Fodda-Signature"] = signature;
186
+ }
187
+ response = await axios.get(`${API_BASE_URL}${getNodePath}`, { headers });
188
+ break;
189
+ }
190
+ case "get_label_values": {
191
+ const getLabelPath = `/v1/graphs/${graphId}/labels/${args?.label}/values`;
192
+ const getLabelSecret = process.env.FODDA_MCP_SECRET;
193
+ if (getLabelSecret) {
194
+ const payload = timestamp + "." + getLabelPath;
195
+ const signature = crypto.createHmac("sha256", getLabelSecret).update(payload).digest("hex");
196
+ headers["X-Fodda-Signature"] = signature;
197
+ }
198
+ response = await axios.get(`${API_BASE_URL}${getLabelPath}`, { headers });
199
+ break;
200
+ }
201
+ case "psfk_overview": {
202
+ // Logic: At least one of industry or sector is required
203
+ const industry = args?.industry;
204
+ const sector = args?.sector;
205
+ if (!industry && !sector) {
206
+ throw new Error("At least one of 'industry' or 'sector' must be provided for psfk_overview.");
207
+ }
208
+ const body = {
209
+ industry,
210
+ sector,
211
+ region: args?.region,
212
+ timeframe: args?.timeframe,
213
+ };
214
+ signRequest(body);
215
+ response = await axios.post(`${API_BASE_URL}/v1/psfk/overview`, body, { headers });
216
+ break;
217
+ }
218
+ default:
219
+ throw new Error(`Unknown tool: ${name}`);
220
+ }
221
+ const durationMs = Date.now() - startTime;
222
+ const usage = response.data.usage || { total_billable_units: 0 };
223
+ // Structured Audit Log for Enterprise Traceability (Refined for Security Compliance)
224
+ console.error(JSON.stringify({
225
+ event: "mcp.tool_call",
226
+ tool: name,
227
+ graphId,
228
+ userId, // Corresponds to tenant/user identity
229
+ status: response.status,
230
+ durationMs,
231
+ billable_units: usage.total_billable_units,
232
+ deterministic: false,
233
+ layer: "mcp_proxy"
234
+ }));
235
+ return {
236
+ content: [{ type: "text", text: JSON.stringify(response.data, null, 2) }]
237
+ };
238
+ }
239
+ catch (error) {
240
+ const durationMs = Date.now() - startTime;
241
+ console.error(JSON.stringify({
242
+ event: "mcp.tool_error",
243
+ tool: name,
244
+ graphId,
245
+ userId,
246
+ status: error.response?.status || 500,
247
+ durationMs,
248
+ error: error.response?.data?.message || error.message
249
+ }));
250
+ return {
251
+ isError: true,
252
+ content: [{ type: "text", text: `Error calling Fodda API: ${error.response?.data?.message || error.message}` }],
253
+ };
254
+ }
255
+ });
256
+ /**
257
+ * Start the server.
258
+ */
259
+ async function main() {
260
+ if (process.env.PORT) {
261
+ const app = express();
262
+ const port = parseInt(process.env.PORT) || 8080;
263
+ const transports = new Map();
264
+ // Security: HMAC Signature Verification Middleware
265
+ const verifySignature = (req, res, next) => {
266
+ // Skip verification for public/health endpoints
267
+ if ((req.path === "/mcp/tools" || req.path === "/health" || req.path === "/.well-known/mcp.json") && req.method === "GET") {
268
+ return next();
269
+ }
270
+ const signature = req.headers["x-fodda-signature"];
271
+ const secret = process.env.FODDA_MCP_SECRET;
272
+ if (!secret) {
273
+ console.error("CRITICAL: FODDA_MCP_SECRET not set in environment.");
274
+ return res.status(500).json({ error: "Server misconfiguration" });
275
+ }
276
+ if (!signature || typeof signature !== 'string') {
277
+ return res.status(401).json({ error: "Missing or invalid signature" });
278
+ }
279
+ const payload = JSON.stringify(req.body);
280
+ const expectedSignature = crypto
281
+ .createHmac("sha256", secret)
282
+ .update(payload)
283
+ .digest("hex");
284
+ // Timing-safe comparison
285
+ const trusted = Buffer.from(expectedSignature, 'ascii');
286
+ const untrusted = Buffer.from(signature, 'ascii');
287
+ if (trusted.length !== untrusted.length || !crypto.timingSafeEqual(trusted, untrusted)) {
288
+ console.error("❌ Invalid Signature:", signature, "Expected:", expectedSignature);
289
+ return res.status(401).json({ error: "Invalid signature" });
290
+ }
291
+ next();
292
+ };
293
+ // --- Per-Key Rate Limiting ---
294
+ const RATE_LIMIT_WINDOW_MS = 60_000; // 1 minute
295
+ const RATE_LIMIT_MAX = parseInt(process.env.RATE_LIMIT_RPM || "60", 10);
296
+ const rateLimitMap = new Map();
297
+ // Clean up expired entries every 5 minutes
298
+ setInterval(() => {
299
+ const now = Date.now();
300
+ for (const [key, entry] of rateLimitMap) {
301
+ if (now - entry.windowStart > RATE_LIMIT_WINDOW_MS * 2) {
302
+ rateLimitMap.delete(key);
303
+ }
304
+ }
305
+ }, 5 * 60_000);
306
+ const rateLimiter = (req, res, next) => {
307
+ // Skip rate limiting for public/health endpoints
308
+ if ((req.path === "/mcp/tools" || req.path === "/health" || req.path === "/.well-known/mcp.json") && req.method === "GET") {
309
+ return next();
310
+ }
311
+ // Extract key from API key header or fallback to IP
312
+ const apiKey = req.headers["x-api-key"] || req.ip || "unknown";
313
+ const now = Date.now();
314
+ const entry = rateLimitMap.get(apiKey);
315
+ if (!entry || now - entry.windowStart > RATE_LIMIT_WINDOW_MS) {
316
+ // New window
317
+ rateLimitMap.set(apiKey, { count: 1, windowStart: now });
318
+ }
319
+ else {
320
+ entry.count++;
321
+ if (entry.count > RATE_LIMIT_MAX) {
322
+ const retryAfter = Math.ceil((entry.windowStart + RATE_LIMIT_WINDOW_MS - now) / 1000);
323
+ console.error(JSON.stringify({
324
+ event: "mcp.rate_limit",
325
+ apiKey: apiKey.substring(0, 8) + "...",
326
+ count: entry.count,
327
+ limit: RATE_LIMIT_MAX,
328
+ }));
329
+ res.set("Retry-After", String(retryAfter));
330
+ return res.status(429).json({
331
+ error: "Rate limit exceeded",
332
+ limit: RATE_LIMIT_MAX,
333
+ window: "60s",
334
+ retry_after: retryAfter,
335
+ });
336
+ }
337
+ }
338
+ // Set rate limit headers
339
+ const current = rateLimitMap.get(apiKey);
340
+ res.set("X-RateLimit-Limit", String(RATE_LIMIT_MAX));
341
+ res.set("X-RateLimit-Remaining", String(Math.max(0, RATE_LIMIT_MAX - current.count)));
342
+ res.set("X-RateLimit-Reset", String(Math.ceil((current.windowStart + RATE_LIMIT_WINDOW_MS) / 1000)));
343
+ next();
344
+ };
345
+ // Parse JSON bodies with size limit (required for signature verification)
346
+ app.use(express.json({ limit: '1mb' }));
347
+ // Rate limiting (before HMAC to reject early)
348
+ app.use(rateLimiter);
349
+ // HMAC Signature Verification
350
+ app.use(verifySignature);
351
+ app.get("/sse", async (req, res) => {
352
+ const sessionId = crypto.randomUUID();
353
+ console.error(`New SSE connection established (session: ${sessionId})`);
354
+ const transport = new SSEServerTransport("/messages", res);
355
+ transports.set(sessionId, transport);
356
+ // Clean up on disconnect
357
+ res.on("close", () => {
358
+ transports.delete(sessionId);
359
+ console.error(`SSE session ${sessionId} disconnected (${transports.size} active)`);
360
+ });
361
+ await server.connect(transport);
362
+ });
363
+ app.post("/messages", async (req, res) => {
364
+ // Find the appropriate transport by checking the sessionId query param
365
+ const sessionId = req.query.sessionId;
366
+ if (sessionId && transports.has(sessionId)) {
367
+ await transports.get(sessionId).handlePostMessage(req, res);
368
+ }
369
+ else if (transports.size === 1) {
370
+ // Fallback: single-client mode
371
+ const [transport] = transports.values();
372
+ await transport.handlePostMessage(req, res);
373
+ }
374
+ else if (transports.size === 0) {
375
+ res.status(400).send("No SSE connections established");
376
+ }
377
+ else {
378
+ res.status(400).send("Multiple SSE sessions active. Specify sessionId query parameter.");
379
+ }
380
+ });
381
+ // Health check for Cloud Run liveness/readiness probes
382
+ app.get("/health", (req, res) => {
383
+ res.json({ status: "ok", version: MCP_SERVER_VERSION });
384
+ });
385
+ // Enterprise Transparency: Tool Capability Registry
386
+ app.get("/mcp/tools", (req, res) => {
387
+ res.json({
388
+ tools: TOOLS,
389
+ count: TOOLS.length,
390
+ version: MCP_SERVER_VERSION
391
+ });
392
+ });
393
+ // MCP Server Discovery (emerging .well-known standard)
394
+ app.get("/.well-known/mcp.json", (req, res) => {
395
+ res.json({
396
+ name: "ai.fodda/mcp-server",
397
+ title: "Fodda Knowledge Graphs",
398
+ description: "Expert-curated knowledge graphs for AI agents — PSFK Retail, Beauty, Sports and more.",
399
+ version: MCP_SERVER_VERSION,
400
+ transport: {
401
+ type: "sse",
402
+ url: `${req.protocol}://${req.get("host")}/sse`
403
+ },
404
+ tools_endpoint: `${req.protocol}://${req.get("host")}/mcp/tools`,
405
+ health_endpoint: `${req.protocol}://${req.get("host")}/health`
406
+ });
407
+ });
408
+ const httpServer = app.listen(port, () => {
409
+ console.error(`Fodda MCP server running on SSE at http://localhost:${port}/sse`);
410
+ });
411
+ // Graceful shutdown for Cloud Run
412
+ const shutdown = () => {
413
+ console.error("Shutting down gracefully...");
414
+ httpServer.close(() => {
415
+ console.error(`Closed ${transports.size} active SSE connections.`);
416
+ process.exit(0);
417
+ });
418
+ // Force exit after 10s if connections don't close
419
+ setTimeout(() => process.exit(1), 10000);
420
+ };
421
+ process.on("SIGTERM", shutdown);
422
+ process.on("SIGINT", shutdown);
423
+ }
424
+ else {
425
+ const transport = new StdioServerTransport();
426
+ await server.connect(transport);
427
+ console.error("Fodda MCP server running on stdio");
428
+ }
429
+ }
430
+ main().catch((error) => {
431
+ console.error("Server error:", error);
432
+ process.exit(1);
433
+ });
434
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=simulate_gemini.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"simulate_gemini.d.ts","sourceRoot":"","sources":["../../scripts/simulate_gemini.ts"],"names":[],"mappings":""}