fodda-mcp 1.3.2 → 1.30.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/LICENSE +31 -0
- package/README.md +192 -20
- package/dist/a2aHandler.d.ts +20 -0
- package/dist/a2aHandler.d.ts.map +1 -0
- package/dist/a2aHandler.js +247 -0
- package/dist/a2aHandler.js.map +1 -0
- package/dist/agents/fodda-researcher/index.d.ts +35 -0
- package/dist/agents/fodda-researcher/index.d.ts.map +1 -0
- package/dist/agents/fodda-researcher/index.js +62 -0
- package/dist/agents/fodda-researcher/index.js.map +1 -0
- package/dist/agents/fodda-researcher/skills.d.ts +16 -0
- package/dist/agents/fodda-researcher/skills.d.ts.map +1 -0
- package/dist/agents/fodda-researcher/skills.js +163 -0
- package/dist/agents/fodda-researcher/skills.js.map +1 -0
- package/dist/brandTemplate.d.ts +14 -0
- package/dist/brandTemplate.d.ts.map +1 -0
- package/dist/brandTemplate.js +742 -0
- package/dist/brandTemplate.js.map +1 -0
- package/dist/catalogCache.d.ts +177 -0
- package/dist/catalogCache.d.ts.map +1 -0
- package/dist/catalogCache.js +708 -0
- package/dist/catalogCache.js.map +1 -0
- package/dist/editorialFill.d.ts +44 -0
- package/dist/editorialFill.d.ts.map +1 -0
- package/dist/editorialFill.js +377 -0
- package/dist/editorialFill.js.map +1 -0
- package/dist/enrichment.d.ts +74 -0
- package/dist/enrichment.d.ts.map +1 -0
- package/dist/enrichment.js +211 -0
- package/dist/enrichment.js.map +1 -0
- package/dist/errorHandling.d.ts +52 -0
- package/dist/errorHandling.d.ts.map +1 -0
- package/dist/errorHandling.js +327 -0
- package/dist/errorHandling.js.map +1 -0
- package/dist/index.d.ts +0 -1
- package/dist/index.js +595 -410
- package/dist/index.js.map +1 -1
- package/dist/pricingCache.d.ts +99 -0
- package/dist/pricingCache.d.ts.map +1 -0
- package/dist/pricingCache.js +414 -0
- package/dist/pricingCache.js.map +1 -0
- package/dist/queryCache.d.ts +25 -0
- package/dist/queryCache.d.ts.map +1 -0
- package/dist/queryCache.js +194 -0
- package/dist/queryCache.js.map +1 -0
- package/dist/searchTemplate.d.ts +16 -0
- package/dist/searchTemplate.d.ts.map +1 -0
- package/dist/searchTemplate.js +318 -0
- package/dist/searchTemplate.js.map +1 -0
- package/dist/sessionTracker.d.ts +39 -0
- package/dist/sessionTracker.d.ts.map +1 -0
- package/dist/sessionTracker.js +187 -0
- package/dist/sessionTracker.js.map +1 -0
- package/dist/skillClient.d.ts +142 -0
- package/dist/skillClient.d.ts.map +1 -0
- package/dist/skillClient.js +256 -0
- package/dist/skillClient.js.map +1 -0
- package/dist/svgVisuals.d.ts +77 -0
- package/dist/svgVisuals.d.ts.map +1 -0
- package/dist/svgVisuals.js +323 -0
- package/dist/svgVisuals.js.map +1 -0
- package/dist/systemPrompt.d.ts +26 -0
- package/dist/systemPrompt.d.ts.map +1 -0
- package/dist/systemPrompt.js +546 -0
- package/dist/systemPrompt.js.map +1 -0
- package/dist/test-waverunner-response.d.ts +2 -0
- package/dist/test-waverunner-response.d.ts.map +1 -0
- package/dist/test-waverunner-response.js +20 -0
- package/dist/test-waverunner-response.js.map +1 -0
- package/dist/test_analyst.d.ts +2 -0
- package/dist/test_analyst.d.ts.map +1 -0
- package/dist/test_analyst.js +39 -0
- package/dist/test_analyst.js.map +1 -0
- package/dist/test_analyst_local.d.ts +2 -0
- package/dist/test_analyst_local.d.ts.map +1 -0
- package/dist/test_analyst_local.js +51 -0
- package/dist/test_analyst_local.js.map +1 -0
- package/dist/test_live_mcp.d.ts +2 -0
- package/dist/test_live_mcp.d.ts.map +1 -0
- package/dist/test_live_mcp.js +49 -0
- package/dist/test_live_mcp.js.map +1 -0
- package/dist/test_skills.d.ts +9 -0
- package/dist/test_skills.d.ts.map +1 -0
- package/dist/test_skills.js +267 -0
- package/dist/test_skills.js.map +1 -0
- package/dist/toolHandlers.d.ts +11 -0
- package/dist/toolHandlers.d.ts.map +1 -0
- package/dist/toolHandlers.js +2829 -0
- package/dist/toolHandlers.js.map +1 -0
- package/dist/tools.d.ts +80 -3
- package/dist/tools.d.ts.map +1 -1
- package/dist/tools.js +89 -186
- package/dist/tools.js.map +1 -1
- package/dist/trialTracker.d.ts +58 -0
- package/dist/trialTracker.d.ts.map +1 -0
- package/dist/trialTracker.js +179 -0
- package/dist/trialTracker.js.map +1 -0
- package/dist/types.d.ts +3 -0
- package/dist/types.d.ts.map +1 -1
- package/dist/verify_hmac.js +1 -1
- package/dist/verify_hmac.js.map +1 -1
- package/dist/verify_tools_endpoint.js +5 -5
- package/dist/verify_tools_endpoint.js.map +1 -1
- package/dist/widgetShell.d.ts +15 -0
- package/dist/widgetShell.d.ts.map +1 -0
- package/dist/widgetShell.js +151 -0
- package/dist/widgetShell.js.map +1 -0
- package/package.json +10 -6
- package/server.json +12 -17
package/LICENSE
ADDED
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
Copyright (c) 2026 Fodda / PSFK. All rights reserved.
|
|
2
|
+
|
|
3
|
+
PROPRIETARY SOFTWARE LICENSE
|
|
4
|
+
|
|
5
|
+
This software and associated documentation files (the "Software") are the
|
|
6
|
+
proprietary and confidential property of Fodda / PSFK ("Fodda"). The Software
|
|
7
|
+
is licensed, not sold.
|
|
8
|
+
|
|
9
|
+
1. Grant. Subject to your compliance with these terms and the Fodda Terms of
|
|
10
|
+
Service (https://www.fodda.ai), Fodda grants you a limited, non-exclusive,
|
|
11
|
+
non-transferable, revocable license to install and run the Software solely
|
|
12
|
+
to connect to the Fodda service using a valid Fodda API key.
|
|
13
|
+
|
|
14
|
+
2. Restrictions. You may not (a) copy, modify, or create derivative works of
|
|
15
|
+
the Software except as required to run it as intended; (b) sell, sublicense,
|
|
16
|
+
rent, lease, or otherwise commercially exploit the Software; (c) reverse
|
|
17
|
+
engineer or attempt to derive the source of any non-public component; or
|
|
18
|
+
(d) remove or alter any proprietary notices.
|
|
19
|
+
|
|
20
|
+
3. Ownership. Fodda retains all right, title, and interest in and to the
|
|
21
|
+
Software, including all intellectual property rights.
|
|
22
|
+
|
|
23
|
+
4. No Warranty. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
|
24
|
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
|
25
|
+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, AND NONINFRINGEMENT.
|
|
26
|
+
|
|
27
|
+
5. Limitation of Liability. IN NO EVENT SHALL FODDA BE LIABLE FOR ANY CLAIM,
|
|
28
|
+
DAMAGES, OR OTHER LIABILITY ARISING FROM OR IN CONNECTION WITH THE SOFTWARE
|
|
29
|
+
OR ITS USE.
|
|
30
|
+
|
|
31
|
+
For licensing inquiries, contact hello@fodda.ai.
|
package/README.md
CHANGED
|
@@ -1,21 +1,100 @@
|
|
|
1
|
-
|
|
1
|
+
<div align="center">
|
|
2
|
+
<img src="https://ucarecdn.com/6e7893d7-6b14-426b-83bc-574a3f72d6bc/foddaminilogo.png" alt="Fodda Logo" width="120"/>
|
|
3
|
+
|
|
4
|
+
# Fodda MCP Server
|
|
2
5
|
|
|
3
|
-
**Expert-curated knowledge graphs for AI agents** — PSFK Retail, Beauty, Sports and partner datasets via the Model Context Protocol.
|
|
6
|
+
**Expert-curated knowledge graphs for AI agents** — PSFK Retail, Beauty, Sports and partner datasets via the Model Context Protocol.
|
|
4
7
|
|
|
5
|
-
[](https://registry.modelcontextprotocol.io/v0.1/servers?search=io.github.piers-fawkes/fodda)
|
|
9
|
+
[](https://www.npmjs.com/package/fodda-mcp)
|
|
10
|
+
[](./CHANGELOG.md)
|
|
11
|
+
[](https://fodda.ai)
|
|
12
|
+
|
|
13
|
+
</div>
|
|
7
14
|
|
|
8
15
|
---
|
|
9
16
|
|
|
10
17
|
## Quick Start
|
|
11
18
|
|
|
12
|
-
### Claude
|
|
19
|
+
### Claude (Web — Pro, Max, Team, Enterprise)
|
|
20
|
+
|
|
21
|
+
**⚡ Quick Connect:** Use this [Add to Claude](https://claude.ai/customize/connectors?modal=add-custom-connector&connectorName=Fodda&connectorUrl=https%3A%2F%2Fmcp.fodda.ai%2Fmcp%3Fapi_key%3DYOUR_API_KEY%26user_id%3DYOUR_EMAIL) quick link (replace `YOUR_API_KEY` and `YOUR_EMAIL` in the URL before pressing enter).
|
|
22
|
+
|
|
23
|
+
**Manual Setup:**
|
|
24
|
+
1. In Claude, go to **Settings → Connectors → Add custom connector**
|
|
25
|
+
2. Enter URL: `https://mcp.fodda.ai/mcp?api_key=YOUR_API_KEY&user_id=YOUR_EMAIL`
|
|
26
|
+
3. Under **Advanced settings** — leave OAuth Client ID and Secret **blank** (Fodda uses API key auth, not OAuth)
|
|
27
|
+
4. Click **Add** — then start chatting with your Fodda knowledge graphs
|
|
28
|
+
|
|
29
|
+
> Get your API key at [app.fodda.ai](https://app.fodda.ai) → Account → MCP Integration.
|
|
30
|
+
> Your API key starts with `sk_live_...`
|
|
31
|
+
> Use the email address associated with your Fodda account for `user_id`.
|
|
32
|
+
|
|
33
|
+
### Claude Code (CLI — SSE)
|
|
13
34
|
|
|
14
35
|
```bash
|
|
15
36
|
claude mcp add --transport sse fodda https://mcp.fodda.ai/sse \
|
|
16
37
|
--header "Authorization: Bearer YOUR_API_KEY"
|
|
17
38
|
```
|
|
18
39
|
|
|
40
|
+
### Claude Enterprise
|
|
41
|
+
|
|
42
|
+
For Claude Enterprise with admin-managed connectors, your workspace admin can register the Fodda MCP server using the same Streamable HTTP endpoint (`https://mcp.fodda.ai/mcp`) via the Admin Console. See [Enterprise MCP Setup](./Enterprise_MCP_Setup.md) for full details.
|
|
43
|
+
|
|
44
|
+
### OpenAI (Responses API — Recommended)
|
|
45
|
+
|
|
46
|
+
Use OpenAI's native MCP support — no function definitions needed:
|
|
47
|
+
|
|
48
|
+
```python
|
|
49
|
+
from openai import OpenAI
|
|
50
|
+
client = OpenAI()
|
|
51
|
+
|
|
52
|
+
resp = client.responses.create(
|
|
53
|
+
model="gpt-5",
|
|
54
|
+
tools=[{
|
|
55
|
+
"type": "mcp",
|
|
56
|
+
"server_label": "fodda",
|
|
57
|
+
"server_description": "Expert-curated knowledge graphs for retail, beauty, sports trends and earnings intelligence.",
|
|
58
|
+
"server_url": "https://mcp.fodda.ai/mcp",
|
|
59
|
+
"authorization": "Bearer YOUR_API_KEY",
|
|
60
|
+
"require_approval": "never",
|
|
61
|
+
}],
|
|
62
|
+
input="What are the top emerging retail trends?",
|
|
63
|
+
)
|
|
64
|
+
print(resp.output_text)
|
|
65
|
+
```
|
|
66
|
+
|
|
67
|
+
```javascript
|
|
68
|
+
import OpenAI from "openai";
|
|
69
|
+
const client = new OpenAI();
|
|
70
|
+
|
|
71
|
+
const resp = await client.responses.create({
|
|
72
|
+
model: "gpt-5",
|
|
73
|
+
tools: [{
|
|
74
|
+
type: "mcp",
|
|
75
|
+
server_label: "fodda",
|
|
76
|
+
server_description: "Expert-curated knowledge graphs for retail, beauty, sports trends and earnings intelligence.",
|
|
77
|
+
server_url: "https://mcp.fodda.ai/mcp",
|
|
78
|
+
authorization: "Bearer YOUR_API_KEY",
|
|
79
|
+
require_approval: "never",
|
|
80
|
+
}],
|
|
81
|
+
input: "What are the top emerging retail trends?",
|
|
82
|
+
});
|
|
83
|
+
console.log(resp.output_text);
|
|
84
|
+
```
|
|
85
|
+
|
|
86
|
+
> **Tip:** To reduce latency with 30+ tools, use `allowed_tools` to filter:
|
|
87
|
+
> `"allowed_tools": ["search_graph", "search_statistics", "brand_tracker"]`
|
|
88
|
+
|
|
89
|
+
> **Legacy:** If you're using `chat.completions.create()` with function calling, define a custom function that calls the Fodda REST API. See [fodda.ai/connect](https://app.fodda.ai) for details.
|
|
90
|
+
|
|
91
|
+
### Generic Streamable HTTP Client
|
|
92
|
+
|
|
93
|
+
Connect to the `/mcp` endpoint using HTTP `POST` (Streamable HTTP) with `Authorization: Bearer YOUR_API_KEY`:
|
|
94
|
+
```
|
|
95
|
+
https://mcp.fodda.ai/mcp
|
|
96
|
+
```
|
|
97
|
+
|
|
19
98
|
### Gemini CLI
|
|
20
99
|
|
|
21
100
|
```json
|
|
@@ -37,16 +116,63 @@ Connect to `https://mcp.fodda.ai/sse` with an `Authorization: Bearer YOUR_API_KE
|
|
|
37
116
|
|
|
38
117
|
## Available Tools
|
|
39
118
|
|
|
119
|
+
The Fodda MCP server exposes a rich suite of 30 tools to search, analyze, brainstorm, and visualize trends, expert-curated knowledge graphs, and corporate documents.
|
|
120
|
+
|
|
121
|
+
### Discovery & Search
|
|
122
|
+
| Tool | Description | Deterministic |
|
|
123
|
+
|------|-------------|:---:|
|
|
124
|
+
| `list_graphs` | Discover available knowledge graphs, metadata, and routing instructions. | ✅ |
|
|
125
|
+
| `search_graph` | Hybrid keyword + semantic search across curated graphs for trend clusters and evidence. | ❌ |
|
|
126
|
+
| `search_statistics` | Search for specific quantitative metrics, indicators, and numeric data points. | ❌ |
|
|
127
|
+
| `search_insights` | Search expert quotes, qualitative signals, and professional interpretations. | ❌ |
|
|
128
|
+
| `get_label_values` | Discover valid values for a node label or category. | ✅ |
|
|
129
|
+
|
|
130
|
+
### Traversal & Graph Operations
|
|
131
|
+
| Tool | Description | Deterministic |
|
|
132
|
+
|------|-------------|:---:|
|
|
133
|
+
| `get_neighbors` | Traverse from seed nodes to discover related concept nodes and links. | ✅ |
|
|
134
|
+
| `get_node` | Retrieve detailed metadata, properties, and attributes for a single node by ID. | ✅ |
|
|
135
|
+
| `get_evidence` | Retrieve source signals, articles, citations, and provenance for a trend or node. | ✅ |
|
|
136
|
+
| `discover_adjacent_trends` | Find semantically similar trends to a given trend node. | ✅ |
|
|
137
|
+
|
|
138
|
+
### Intelligence Domains
|
|
40
139
|
| Tool | Description | Deterministic |
|
|
41
140
|
|------|-------------|:---:|
|
|
42
|
-
| `
|
|
43
|
-
| `
|
|
44
|
-
| `
|
|
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 | ❌ |
|
|
141
|
+
| `get_domain_intelligence` | Search all PSFK curated domain graphs (retail, beauty, sports, fashion, consumer electronics, F&B) in parallel. | ❌ |
|
|
142
|
+
| `get_expert_intelligence` | Query specialist industry graphs built by leading strategists and experts. | ❌ |
|
|
143
|
+
| `get_report_intelligence` | Search institutional report insights from DHL, PwC, Delta, and other partners. | ❌ |
|
|
48
144
|
|
|
49
|
-
|
|
145
|
+
### Earnings & Corporate Insights
|
|
146
|
+
| Tool | Description | Deterministic |
|
|
147
|
+
|------|-------------|:---:|
|
|
148
|
+
| `get_earnings_intelligence` | Query management commentary, business guidance, and Q&A from company earnings calls. | ❌ |
|
|
149
|
+
| `get_earnings_divergence` | Detect deflections, gaps, and divergence between analyst concerns and executive responses in earnings calls. | ❌ |
|
|
150
|
+
|
|
151
|
+
### Brand & Ideation
|
|
152
|
+
| Tool | Description | Deterministic |
|
|
153
|
+
|------|-------------|:---:|
|
|
154
|
+
| `brand_tracker` | Compile a comprehensive Brand Intelligence Profile across all knowledge graphs. | ❌ |
|
|
155
|
+
| `brainstorm_topic` | Graph-powered brainstorm map discovering unexpected connections and adjacent territories. | ❌ |
|
|
156
|
+
|
|
157
|
+
### Deep Research & Execution Agents
|
|
158
|
+
| Tool | Description | Deterministic |
|
|
159
|
+
|------|-------------|:---:|
|
|
160
|
+
| `deep_research_topic` | Launch an autonomous research session combining graphs with live web search. | ❌ |
|
|
161
|
+
| `check_research_status` | Check progress or retrieve the final narrative report of a deep research job. | ✅ |
|
|
162
|
+
| `get_supplemental_context` | Fetch macro context from up to 10 institutional data sources in a single query. | ❌ |
|
|
163
|
+
| `check_supplemental_status` | Retrieve output from a supplemental context job. | ✅ |
|
|
164
|
+
|
|
165
|
+
### Synthetic Analyst & Visualization
|
|
166
|
+
| Tool | Description | Deterministic |
|
|
167
|
+
|------|-------------|:---:|
|
|
168
|
+
| `list_analysts` | List available Synthetic Analyst expert personas. | ✅ |
|
|
169
|
+
| `consult_analyst` | Engage a Synthetic Analyst persona to synthesize answers with specialized voice. | ❌ |
|
|
170
|
+
| `generate_visual` | Generate branded SVG data visualizations (Cultural Shifts, Competitive Compass, Innovation Pathway, etc.). | ❌ |
|
|
171
|
+
> **Note on Dynamic Partner Skills:** When partner skills (such as Paralogy or Igloo) are enabled for a user's account, additional specialized tools (e.g. `paralogy_analyze_trends`, ideation tools) are dynamically registered on the MCP server and made available automatically.
|
|
172
|
+
>
|
|
173
|
+
> **Note on System Utilities:** The server also registers several helper and account management utilities (e.g., `get_my_account`, `toggle_graph_preference`, `update_user_profile`, `manage_scheduled_reports`, `send_feedback`) to allow the AI assistant to query subscription status, manage scheduled briefings, or save personalization settings directly.
|
|
174
|
+
|
|
175
|
+
---
|
|
50
176
|
|
|
51
177
|
### Discovery Endpoints
|
|
52
178
|
|
|
@@ -60,29 +186,36 @@ All tools require `userId` and — except `psfk_overview` — a `graphId`.
|
|
|
60
186
|
|
|
61
187
|
## Authentication
|
|
62
188
|
|
|
189
|
+
**Preferred — HTTP header (used by the directory connection and all header-capable clients).**
|
|
63
190
|
Pass your Fodda API key as a Bearer token:
|
|
64
191
|
|
|
65
192
|
```
|
|
66
|
-
Authorization: Bearer
|
|
193
|
+
Authorization: Bearer sk_live_...
|
|
67
194
|
```
|
|
68
195
|
|
|
196
|
+
The server also accepts the key via an `X-API-Key: sk_live_...` header.
|
|
197
|
+
|
|
69
198
|
In MCP request `_meta`:
|
|
70
199
|
```json
|
|
71
|
-
{ "_meta": { "authorization": "Bearer
|
|
200
|
+
{ "_meta": { "authorization": "Bearer sk_live_..." } }
|
|
72
201
|
```
|
|
73
202
|
|
|
203
|
+
**Fallback — URL query parameter.** Some clients (e.g. the Claude.ai web *custom
|
|
204
|
+
connector* UI) cannot set custom request headers. For those, the key may be passed as
|
|
205
|
+
`?api_key=...`. This is provided only for compatibility; prefer header-based auth
|
|
206
|
+
wherever the client supports it, since URLs are more likely to be logged by
|
|
207
|
+
intermediaries. The server never returns your API key in tool output.
|
|
208
|
+
|
|
74
209
|
---
|
|
75
210
|
|
|
76
211
|
## Configuration
|
|
77
212
|
|
|
78
213
|
| Variable | Description | Default |
|
|
79
214
|
|----------|-------------|---------|
|
|
80
|
-
| `PORT` |
|
|
215
|
+
| `PORT` | HTTP server port (omit for stdio mode) | — |
|
|
81
216
|
| `FODDA_API_URL` | Upstream API base URL | `https://api.fodda.ai` |
|
|
82
|
-
| `FODDA_MCP_SECRET` | HMAC signing secret | — |
|
|
217
|
+
| `FODDA_MCP_SECRET` | HMAC signing secret for API requests | — |
|
|
83
218
|
| `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
219
|
|
|
87
220
|
---
|
|
88
221
|
|
|
@@ -110,15 +243,54 @@ PORT=8080 npm start
|
|
|
110
243
|
|
|
111
244
|
## MCP Registry
|
|
112
245
|
|
|
113
|
-
This server is published to the [Official MCP Registry](https://registry.modelcontextprotocol.io) as `
|
|
246
|
+
This server is published to the [Official MCP Registry](https://registry.modelcontextprotocol.io) as `io.github.piers-fawkes/fodda`.
|
|
114
247
|
|
|
115
248
|
```bash
|
|
116
249
|
# Verify listing
|
|
117
|
-
curl "https://registry.modelcontextprotocol.io/v0.1/servers?search=
|
|
250
|
+
curl "https://registry.modelcontextprotocol.io/v0.1/servers?search=io.github.piers-fawkes/fodda"
|
|
118
251
|
```
|
|
119
252
|
|
|
120
253
|
---
|
|
121
254
|
|
|
255
|
+
## Privacy Policy
|
|
256
|
+
|
|
257
|
+
Full policy: **[https://www.fodda.ai/privacy](https://www.fodda.ai/privacy)**
|
|
258
|
+
|
|
259
|
+
Summary of how the Fodda MCP server handles data:
|
|
260
|
+
|
|
261
|
+
- **What we collect.** Your Fodda API key (for authentication and billing) and the
|
|
262
|
+
`user_id`/email associated with your Fodda account. Tool calls you make (queries,
|
|
263
|
+
parameters, and the graphs/skills accessed) are processed to return results and may
|
|
264
|
+
be logged for reliability, abuse prevention, and usage metering.
|
|
265
|
+
- **How it's used and stored.** Requests are proxied to the Fodda API
|
|
266
|
+
(`https://api.fodda.ai`) over HTTPS. Session and account state is stored in Fodda's
|
|
267
|
+
managed infrastructure. Your API key is transmitted only to authenticate your
|
|
268
|
+
requests and is never returned in tool output.
|
|
269
|
+
- **Third-party sharing.** We do not sell your data. Query content may be processed by
|
|
270
|
+
sub-processors strictly to deliver the service (e.g. model inference and
|
|
271
|
+
transactional email providers). Partner "skills," when enabled by you, process only
|
|
272
|
+
the queries you direct to them.
|
|
273
|
+
- **Retention.** Account and usage records are retained while your account is active
|
|
274
|
+
and for the period required for billing, security, and legal obligations. See the
|
|
275
|
+
hosted policy for specifics.
|
|
276
|
+
- **Contact.** Privacy questions: **[hello@fodda.ai](mailto:hello@fodda.ai)**.
|
|
277
|
+
|
|
278
|
+
See the [full hosted Privacy Policy](https://www.fodda.ai/privacy) for the complete,
|
|
279
|
+
authoritative terms.
|
|
280
|
+
|
|
281
|
+
---
|
|
282
|
+
|
|
283
|
+
## Support
|
|
284
|
+
|
|
285
|
+
- **Email:** [hello@fodda.ai](mailto:hello@fodda.ai)
|
|
286
|
+
- **Account & API keys:** [app.fodda.ai](https://app.fodda.ai) → Account → MCP Integration
|
|
287
|
+
- **Documentation:** [fodda.ai](https://www.fodda.ai)
|
|
288
|
+
|
|
289
|
+
To report a security issue, email **[hello@fodda.ai](mailto:hello@fodda.ai)** with
|
|
290
|
+
"SECURITY" in the subject line.
|
|
291
|
+
|
|
292
|
+
---
|
|
293
|
+
|
|
122
294
|
## License
|
|
123
295
|
|
|
124
296
|
Proprietary — [fodda.ai](https://www.fodda.ai)
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* A2A (Agent-to-Agent) Protocol Handler
|
|
3
|
+
*
|
|
4
|
+
* Implements JSON-RPC 2.0 over HTTP per the A2A v1.0 specification.
|
|
5
|
+
* MVP: Supports `message/send` only — receives a natural language task,
|
|
6
|
+
* routes it through Fodda's existing tool handlers, and returns
|
|
7
|
+
* structured results as A2A Task artifacts.
|
|
8
|
+
*
|
|
9
|
+
* A2A vs MCP:
|
|
10
|
+
* - MCP: client agent calls Fodda tools directly (tool-level granularity)
|
|
11
|
+
* - A2A: client agent delegates a *task* in natural language; Fodda decides
|
|
12
|
+
* which tools to use and returns the synthesized result
|
|
13
|
+
*
|
|
14
|
+
* Spec: https://a2a-protocol.org/latest/specification/
|
|
15
|
+
*/
|
|
16
|
+
import type { Express } from 'express';
|
|
17
|
+
type FoddaRequestFn = (method: 'GET' | 'POST' | 'PATCH', path: string, apiKey: string, userId: string, body?: any) => Promise<any>;
|
|
18
|
+
export declare function registerA2ARoute(app: Express, foddaRequest: FoddaRequestFn): void;
|
|
19
|
+
export {};
|
|
20
|
+
//# sourceMappingURL=a2aHandler.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"a2aHandler.d.ts","sourceRoot":"","sources":["../src/a2aHandler.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;GAcG;AAGH,OAAO,KAAK,EAAE,OAAO,EAAqB,MAAM,SAAS,CAAC;AAsF1D,KAAK,cAAc,GAAG,CAClB,MAAM,EAAE,KAAK,GAAG,MAAM,GAAG,OAAO,EAChC,IAAI,EAAE,MAAM,EACZ,MAAM,EAAE,MAAM,EACd,MAAM,EAAE,MAAM,EACd,IAAI,CAAC,EAAE,GAAG,KACT,OAAO,CAAC,GAAG,CAAC,CAAC;AAgIlB,wBAAgB,gBAAgB,CAC5B,GAAG,EAAE,OAAO,EACZ,YAAY,EAAE,cAAc,GAC7B,IAAI,CAwIN"}
|
|
@@ -0,0 +1,247 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* A2A (Agent-to-Agent) Protocol Handler
|
|
3
|
+
*
|
|
4
|
+
* Implements JSON-RPC 2.0 over HTTP per the A2A v1.0 specification.
|
|
5
|
+
* MVP: Supports `message/send` only — receives a natural language task,
|
|
6
|
+
* routes it through Fodda's existing tool handlers, and returns
|
|
7
|
+
* structured results as A2A Task artifacts.
|
|
8
|
+
*
|
|
9
|
+
* A2A vs MCP:
|
|
10
|
+
* - MCP: client agent calls Fodda tools directly (tool-level granularity)
|
|
11
|
+
* - A2A: client agent delegates a *task* in natural language; Fodda decides
|
|
12
|
+
* which tools to use and returns the synthesized result
|
|
13
|
+
*
|
|
14
|
+
* Spec: https://a2a-protocol.org/latest/specification/
|
|
15
|
+
*/
|
|
16
|
+
import crypto from 'crypto';
|
|
17
|
+
function classifyIntent(text) {
|
|
18
|
+
const lower = text.toLowerCase();
|
|
19
|
+
// Brand-focused queries
|
|
20
|
+
const brandMatch = lower.match(/(?:what is |what's |tell me about |brand (?:intelligence|profile|tracker) (?:for |on )?|track )([a-z][a-z0-9 &'.-]{1,30}?)(?:\s+(?:doing|strategy|innovation|positioning|trends?))?$/i);
|
|
21
|
+
if (brandMatch && brandMatch[1]) {
|
|
22
|
+
return { tool: 'brand_tracker', params: { brand_name: brandMatch[1].trim() } };
|
|
23
|
+
}
|
|
24
|
+
// Explicit brand mentions with "what is X doing" pattern
|
|
25
|
+
const doingMatch = text.match(/what (?:is|are) ([A-Z][A-Za-z0-9 &'.-]{1,30}?) doing/);
|
|
26
|
+
if (doingMatch && doingMatch[1]) {
|
|
27
|
+
return { tool: 'brand_tracker', params: { brand_name: doingMatch[1].trim() } };
|
|
28
|
+
}
|
|
29
|
+
// Deep research triggers
|
|
30
|
+
if (lower.includes('deep research') || lower.includes('comprehensive report') ||
|
|
31
|
+
lower.includes('write me a report') || lower.includes('detailed analysis')) {
|
|
32
|
+
return { tool: 'deep_research', params: { query: text, depth: 'light' } };
|
|
33
|
+
}
|
|
34
|
+
// Earnings triggers
|
|
35
|
+
if (lower.includes('earnings') || lower.includes('q1 ') || lower.includes('q2 ') ||
|
|
36
|
+
lower.includes('q3 ') || lower.includes('q4 ') || lower.match(/what (?:are|did) .+ (?:companies|brands) say/)) {
|
|
37
|
+
return { tool: 'earnings', params: { query: text } };
|
|
38
|
+
}
|
|
39
|
+
// Default: search_graph (the most general tool)
|
|
40
|
+
return { tool: 'search_graph', params: { query: text } };
|
|
41
|
+
}
|
|
42
|
+
async function executeQuery(route, apiKey, userId, foddaRequest) {
|
|
43
|
+
switch (route.tool) {
|
|
44
|
+
case 'search_graph': {
|
|
45
|
+
// Search ALL graphs (no graphId = all-graph parallel search)
|
|
46
|
+
const body = {
|
|
47
|
+
query: route.params.query,
|
|
48
|
+
limit: 10,
|
|
49
|
+
use_semantic: true,
|
|
50
|
+
include_evidence: true,
|
|
51
|
+
};
|
|
52
|
+
const result = await foddaRequest('POST', '/v1/graphs/search', apiKey, userId, body);
|
|
53
|
+
const rows = result?.rows || [];
|
|
54
|
+
if (rows.length === 0) {
|
|
55
|
+
return { text: `No trends found for: "${route.params.query}". Fodda's knowledge graphs may not have coverage on this specific topic.`, data: result };
|
|
56
|
+
}
|
|
57
|
+
// Build a concise markdown summary
|
|
58
|
+
const lines = [];
|
|
59
|
+
lines.push(`## Fodda Trend Intelligence: ${route.params.query}\n`);
|
|
60
|
+
lines.push(`_${rows.length} trends found across Fodda's expert-curated knowledge graphs._\n`);
|
|
61
|
+
for (const row of rows.slice(0, 8)) {
|
|
62
|
+
const score = row.signal_score ? ` (signal: ${row.signal_score})` : '';
|
|
63
|
+
const lifecycle = row.trendLifecycle ? ` · ${row.trendLifecycle}` : '';
|
|
64
|
+
const graph = row.graphName ? ` — _${row.graphName}_` : '';
|
|
65
|
+
lines.push(`### ${row.title || row.trendName}${score}${lifecycle}`);
|
|
66
|
+
if (row.summary || row.description) {
|
|
67
|
+
lines.push((row.summary || row.description).substring(0, 300));
|
|
68
|
+
}
|
|
69
|
+
if (row.evidence && row.evidence.length > 0) {
|
|
70
|
+
lines.push('');
|
|
71
|
+
for (const ev of row.evidence.slice(0, 3)) {
|
|
72
|
+
const link = ev.sourceUrl ? ` — [source](${ev.sourceUrl})` : '';
|
|
73
|
+
lines.push(`- ${(ev.title || ev.snippet || '').substring(0, 150)}${link}`);
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
lines.push(`${graph}\n`);
|
|
77
|
+
}
|
|
78
|
+
return { text: lines.join('\n'), data: result };
|
|
79
|
+
}
|
|
80
|
+
case 'brand_tracker': {
|
|
81
|
+
const body = { brand_name: route.params.brand_name };
|
|
82
|
+
const result = await foddaRequest('POST', '/v1/brands/intelligence', apiKey, userId, body);
|
|
83
|
+
const lines = [];
|
|
84
|
+
lines.push(`## Brand Intelligence: ${route.params.brand_name}\n`);
|
|
85
|
+
if (result?.trend_footprint) {
|
|
86
|
+
lines.push(`_Appears in ${result.trend_footprint.length} trends across ${result.cross_graph_presence?.length || 0} knowledge graphs._\n`);
|
|
87
|
+
for (const t of (result.trend_footprint || []).slice(0, 6)) {
|
|
88
|
+
const score = t.signal_score ? ` (signal: ${t.signal_score})` : '';
|
|
89
|
+
lines.push(`- **${t.trend_name}**${score} · ${t.lifecycle || 'unknown'} — ${t.graph_name || ''}`);
|
|
90
|
+
}
|
|
91
|
+
}
|
|
92
|
+
if (result?.competitive_context?.co_occurring?.length > 0) {
|
|
93
|
+
lines.push(`\n### Competitive Context`);
|
|
94
|
+
for (const c of result.competitive_context.co_occurring.slice(0, 5)) {
|
|
95
|
+
lines.push(`- ${c.brand} (${c.pressure_type})`);
|
|
96
|
+
}
|
|
97
|
+
}
|
|
98
|
+
return { text: lines.join('\n') || JSON.stringify(result, null, 2), data: result };
|
|
99
|
+
}
|
|
100
|
+
case 'earnings': {
|
|
101
|
+
const body = { query: route.params.query, limit: 10 };
|
|
102
|
+
const result = await foddaRequest('POST', '/v1/earnings/search', apiKey, userId, body);
|
|
103
|
+
return {
|
|
104
|
+
text: result?.summary || JSON.stringify(result, null, 2),
|
|
105
|
+
data: result,
|
|
106
|
+
};
|
|
107
|
+
}
|
|
108
|
+
case 'deep_research': {
|
|
109
|
+
// For A2A MVP, we do a synchronous search (not the async deep_research job)
|
|
110
|
+
// because A2A registries expect a timely response for health probes.
|
|
111
|
+
const body = {
|
|
112
|
+
query: route.params.query,
|
|
113
|
+
limit: 15,
|
|
114
|
+
use_semantic: true,
|
|
115
|
+
include_evidence: true,
|
|
116
|
+
};
|
|
117
|
+
const result = await foddaRequest('POST', '/v1/graphs/search', apiKey, userId, body);
|
|
118
|
+
const rows = result?.rows || [];
|
|
119
|
+
const lines = [];
|
|
120
|
+
lines.push(`## Research Summary: ${route.params.query}\n`);
|
|
121
|
+
lines.push(`_${rows.length} trends analyzed from Fodda's knowledge graph network._\n`);
|
|
122
|
+
for (const row of rows.slice(0, 10)) {
|
|
123
|
+
const score = row.signal_score ? ` (signal: ${row.signal_score})` : '';
|
|
124
|
+
lines.push(`### ${row.title || row.trendName}${score}`);
|
|
125
|
+
if (row.summary || row.description) {
|
|
126
|
+
lines.push((row.summary || row.description).substring(0, 400));
|
|
127
|
+
}
|
|
128
|
+
lines.push('');
|
|
129
|
+
}
|
|
130
|
+
return { text: lines.join('\n'), data: result };
|
|
131
|
+
}
|
|
132
|
+
}
|
|
133
|
+
}
|
|
134
|
+
// ---------------------------------------------------------------------------
|
|
135
|
+
// JSON-RPC helpers
|
|
136
|
+
// ---------------------------------------------------------------------------
|
|
137
|
+
function jsonRpcSuccess(id, result) {
|
|
138
|
+
return { jsonrpc: '2.0', id, result };
|
|
139
|
+
}
|
|
140
|
+
function jsonRpcError(id, code, message, data) {
|
|
141
|
+
return { jsonrpc: '2.0', id, error: { code, message, ...(data ? { data } : {}) } };
|
|
142
|
+
}
|
|
143
|
+
// ---------------------------------------------------------------------------
|
|
144
|
+
// Route registration
|
|
145
|
+
// ---------------------------------------------------------------------------
|
|
146
|
+
export function registerA2ARoute(app, foddaRequest) {
|
|
147
|
+
app.post('/a2a', async (req, res) => {
|
|
148
|
+
// ── Parse & validate JSON-RPC envelope ──
|
|
149
|
+
const body = req.body;
|
|
150
|
+
if (!body || body.jsonrpc !== '2.0') {
|
|
151
|
+
return res.status(400).json(jsonRpcError(body?.id ?? null, -32600, 'Invalid Request: missing jsonrpc 2.0 field'));
|
|
152
|
+
}
|
|
153
|
+
const requestId = body.id ?? null;
|
|
154
|
+
// ── Method dispatch ──
|
|
155
|
+
switch (body.method) {
|
|
156
|
+
case 'message/send':
|
|
157
|
+
break; // handled below
|
|
158
|
+
// Stubs for future methods — return Method Not Found
|
|
159
|
+
case 'message/stream':
|
|
160
|
+
case 'tasks/get':
|
|
161
|
+
case 'tasks/cancel':
|
|
162
|
+
case 'tasks/list':
|
|
163
|
+
return res.json(jsonRpcError(requestId, -32601, `Method not found: ${body.method}. Only message/send is supported in this version.`));
|
|
164
|
+
default:
|
|
165
|
+
return res.json(jsonRpcError(requestId, -32601, `Method not found: ${body.method}`));
|
|
166
|
+
}
|
|
167
|
+
// ── Extract user text from message parts ──
|
|
168
|
+
const message = body.params?.message;
|
|
169
|
+
if (!message?.parts?.length) {
|
|
170
|
+
return res.json(jsonRpcError(requestId, -32602, 'Invalid params: message.parts is required and must be non-empty'));
|
|
171
|
+
}
|
|
172
|
+
const textPart = message.parts.find(p => p.kind === 'text' && p.text);
|
|
173
|
+
if (!textPart?.text) {
|
|
174
|
+
return res.json(jsonRpcError(requestId, -32602, 'Invalid params: no text part found in message'));
|
|
175
|
+
}
|
|
176
|
+
const queryText = textPart.text;
|
|
177
|
+
// ── Authentication ──
|
|
178
|
+
// Accept: Authorization: Bearer <key>, X-API-Key header, or api_key query param
|
|
179
|
+
const apiKey = (req.headers['authorization']?.toString().replace(/^Bearer\s+/i, ''))
|
|
180
|
+
|| req.headers['x-api-key']
|
|
181
|
+
|| req.query.api_key
|
|
182
|
+
|| '';
|
|
183
|
+
const userId = req.headers['x-user-id']
|
|
184
|
+
|| req.query.user_id
|
|
185
|
+
|| 'a2a-agent';
|
|
186
|
+
// For unauthenticated requests (health probes), return a minimal valid response
|
|
187
|
+
if (!apiKey) {
|
|
188
|
+
const taskId = `task-${crypto.randomUUID().slice(0, 8)}`;
|
|
189
|
+
const contextId = `ctx-${crypto.randomUUID().slice(0, 8)}`;
|
|
190
|
+
return res.json(jsonRpcSuccess(requestId, {
|
|
191
|
+
id: taskId,
|
|
192
|
+
contextId,
|
|
193
|
+
status: { state: 'completed' },
|
|
194
|
+
artifacts: [{
|
|
195
|
+
name: 'health_check',
|
|
196
|
+
parts: [{
|
|
197
|
+
kind: 'text',
|
|
198
|
+
text: 'Fodda A2A endpoint is operational. Provide an API key via Authorization: Bearer <key> for full access to trend intelligence. Get a key at https://app.fodda.ai',
|
|
199
|
+
}],
|
|
200
|
+
}],
|
|
201
|
+
}));
|
|
202
|
+
}
|
|
203
|
+
// ── Route and execute ──
|
|
204
|
+
try {
|
|
205
|
+
const route = classifyIntent(queryText);
|
|
206
|
+
console.error(`[a2a] message/send: "${queryText.substring(0, 80)}" → ${route.tool}`);
|
|
207
|
+
const result = await executeQuery(route, apiKey, userId, foddaRequest);
|
|
208
|
+
const taskId = `task-${crypto.randomUUID().slice(0, 8)}`;
|
|
209
|
+
const contextId = `ctx-${crypto.randomUUID().slice(0, 8)}`;
|
|
210
|
+
// Build artifacts — always include markdown text, optionally raw JSON
|
|
211
|
+
const artifacts = [
|
|
212
|
+
{
|
|
213
|
+
name: 'research_result',
|
|
214
|
+
description: `Fodda intelligence for: ${queryText.substring(0, 100)}`,
|
|
215
|
+
parts: [{ kind: 'text', text: result.text }],
|
|
216
|
+
},
|
|
217
|
+
];
|
|
218
|
+
// Include raw data as a structured artifact if the client accepts JSON
|
|
219
|
+
const acceptedOutputs = body.params?.configuration?.acceptedOutputModes || [];
|
|
220
|
+
if (acceptedOutputs.includes('application/json') && result.data) {
|
|
221
|
+
artifacts.push({
|
|
222
|
+
name: 'raw_data',
|
|
223
|
+
description: 'Structured JSON data from Fodda knowledge graphs',
|
|
224
|
+
parts: [{ kind: 'data', data: result.data, mimeType: 'application/json' }],
|
|
225
|
+
});
|
|
226
|
+
}
|
|
227
|
+
return res.json(jsonRpcSuccess(requestId, {
|
|
228
|
+
id: taskId,
|
|
229
|
+
contextId,
|
|
230
|
+
status: { state: 'completed' },
|
|
231
|
+
artifacts,
|
|
232
|
+
}));
|
|
233
|
+
}
|
|
234
|
+
catch (err) {
|
|
235
|
+
const statusCode = err.response?.status;
|
|
236
|
+
const errMsg = err.response?.data?.error?.message || err.message || 'Internal error';
|
|
237
|
+
console.error(`[a2a] Error: ${errMsg}`);
|
|
238
|
+
// Map known error types to appropriate JSON-RPC error codes
|
|
239
|
+
if (statusCode === 401 || statusCode === 403) {
|
|
240
|
+
return res.json(jsonRpcError(requestId, -32001, `Unauthorized: ${errMsg}`));
|
|
241
|
+
}
|
|
242
|
+
return res.json(jsonRpcError(requestId, -32603, `Fodda query failed: ${errMsg}`));
|
|
243
|
+
}
|
|
244
|
+
});
|
|
245
|
+
console.error('[a2a] A2A endpoint registered at POST /a2a');
|
|
246
|
+
}
|
|
247
|
+
//# sourceMappingURL=a2aHandler.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"a2aHandler.js","sourceRoot":"","sources":["../src/a2aHandler.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Fodda Research Agent — System Instruction Builder
|
|
3
|
+
*
|
|
4
|
+
* Loads the 5 skill files and assembles a system instruction for the
|
|
5
|
+
* Gemini Interactions API. This is the "agent" — a skill-injected system
|
|
6
|
+
* prompt that tells Gemini how to conduct Fodda-style research.
|
|
7
|
+
*
|
|
8
|
+
* Usage:
|
|
9
|
+
* import { buildResearcherInstruction } from './agents/fodda-researcher/index.js';
|
|
10
|
+
* const systemInstruction = buildResearcherInstruction(query, graphContext);
|
|
11
|
+
*/
|
|
12
|
+
/**
|
|
13
|
+
* Context about pre-fetched Fodda graph results, injected into the
|
|
14
|
+
* system instruction so the agent can reference existing knowledge.
|
|
15
|
+
*/
|
|
16
|
+
export interface GraphContext {
|
|
17
|
+
/** Pre-fetched trends from Fodda graphs, stringified JSON */
|
|
18
|
+
graphResults?: string;
|
|
19
|
+
/** Which graphs were searched */
|
|
20
|
+
graphsSearched?: string[];
|
|
21
|
+
/** Total trends found across all graphs */
|
|
22
|
+
totalTrends?: number;
|
|
23
|
+
/** Total evidence pieces collected */
|
|
24
|
+
totalEvidence?: number;
|
|
25
|
+
/** Optional specific graph to focus on (undefined = search all) */
|
|
26
|
+
focusGraphId?: string | undefined;
|
|
27
|
+
}
|
|
28
|
+
/**
|
|
29
|
+
* Build the complete system instruction for the Fodda Research Agent.
|
|
30
|
+
*
|
|
31
|
+
* Concatenates all 5 skill files with a mission preamble and any
|
|
32
|
+
* graph context that was pre-fetched from Fodda's knowledge graphs.
|
|
33
|
+
*/
|
|
34
|
+
export declare function buildResearcherInstruction(query: string, context?: GraphContext): string;
|
|
35
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/agents/fodda-researcher/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AAUH;;;GAGG;AACH,MAAM,WAAW,YAAY;IACzB,6DAA6D;IAC7D,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,iCAAiC;IACjC,cAAc,CAAC,EAAE,MAAM,EAAE,CAAC;IAC1B,2CAA2C;IAC3C,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,sCAAsC;IACtC,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,mEAAmE;IACnE,YAAY,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;CACrC;AAED;;;;;GAKG;AACH,wBAAgB,0BAA0B,CACtC,KAAK,EAAE,MAAM,EACb,OAAO,CAAC,EAAE,YAAY,GACvB,MAAM,CA8CR"}
|