@flowframe22/mcp-server 0.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.
- package/LICENSE +21 -0
- package/README.md +97 -0
- package/dist/client.d.ts +40 -0
- package/dist/client.js +104 -0
- package/dist/client.js.map +1 -0
- package/dist/formatter.d.ts +40 -0
- package/dist/formatter.js +84 -0
- package/dist/formatter.js.map +1 -0
- package/dist/index.d.ts +23 -0
- package/dist/index.js +54 -0
- package/dist/index.js.map +1 -0
- package/dist/tools.d.ts +11 -0
- package/dist/tools.js +418 -0
- package/dist/tools.js.map +1 -0
- package/package.json +48 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 FlowFrame
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in
|
|
13
|
+
all copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
|
21
|
+
THE SOFTWARE.
|
package/README.md
ADDED
|
@@ -0,0 +1,97 @@
|
|
|
1
|
+
# @flowframe22/mcp-server
|
|
2
|
+
|
|
3
|
+
[Model Context Protocol](https://modelcontextprotocol.io) server for [FlowFrame](https://flowframe.xyz) — bring prediction‑market intelligence (Polymarket movers, smart‑money skew, FlowFrame Pulse, political mentions) into Claude and any MCP‑compatible client.
|
|
4
|
+
|
|
5
|
+
Ask Claude things like:
|
|
6
|
+
|
|
7
|
+
- *"What Polymarket markets moved most in the last 4 hours?"*
|
|
8
|
+
- *"Where is smart money disagreeing with the market right now?"*
|
|
9
|
+
- *"When did Powell last mention tariffs in a press conference?"*
|
|
10
|
+
- *"What is FlowFrame saying about the 2026 midterm Senate races?"*
|
|
11
|
+
|
|
12
|
+
Claude calls FlowFrame, you get an answer with sources and a link back to flowframe.xyz.
|
|
13
|
+
|
|
14
|
+
## Setup
|
|
15
|
+
|
|
16
|
+
### 1. Get a FlowFrame API key
|
|
17
|
+
|
|
18
|
+
Free, takes 10 seconds: <https://flowframe.xyz/account/api-keys>
|
|
19
|
+
|
|
20
|
+
### 2. Add the server to Claude Desktop
|
|
21
|
+
|
|
22
|
+
Edit your Claude Desktop config:
|
|
23
|
+
|
|
24
|
+
- **macOS:** `~/Library/Application Support/Claude/claude_desktop_config.json`
|
|
25
|
+
- **Windows:** `%APPDATA%\Claude\claude_desktop_config.json`
|
|
26
|
+
|
|
27
|
+
```json
|
|
28
|
+
{
|
|
29
|
+
"mcpServers": {
|
|
30
|
+
"flowframe": {
|
|
31
|
+
"command": "npx",
|
|
32
|
+
"args": ["-y", "@flowframe22/mcp-server"],
|
|
33
|
+
"env": {
|
|
34
|
+
"FLOWFRAME_API_KEY": "flowframe_live_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
```
|
|
40
|
+
|
|
41
|
+
Restart Claude Desktop. You should see a hammer icon indicating tools are available.
|
|
42
|
+
|
|
43
|
+
### 3. (Optional) Use with Claude Code or other MCP clients
|
|
44
|
+
|
|
45
|
+
Any client that speaks MCP over stdio works the same way — point it at `npx -y @flowframe22/mcp-server` with `FLOWFRAME_API_KEY` in the environment.
|
|
46
|
+
|
|
47
|
+
## Tools
|
|
48
|
+
|
|
49
|
+
| Tool | Description |
|
|
50
|
+
|---|---|
|
|
51
|
+
| `flowframe_ping` | Health check — confirm your API key works inside Claude |
|
|
52
|
+
| `flowframe_list_pulse` | Recent FlowFrame Pulse analysis items |
|
|
53
|
+
| `flowframe_get_pulse_item` | Fetch a single Pulse item by slug or uuid (full content) |
|
|
54
|
+
| `flowframe_get_pulse_for_market` | All FlowFrame coverage of a specific Polymarket market (by conditionId) |
|
|
55
|
+
| `flowframe_polymarket_movers` | Top Polymarket markets by recent price change (1h/4h/12h/24h) |
|
|
56
|
+
| `flowframe_kalshi_movers` | Top Kalshi markets by recent price change |
|
|
57
|
+
| `flowframe_smart_money_skew` | Markets where the top 30 profitable traders disagree with the market |
|
|
58
|
+
| `flowframe_smart_money_skew_for_market` | Per-tier breakdown for a single market |
|
|
59
|
+
| `flowframe_list_speakers` | List indexed political speakers (Trump, Powell, Vance, etc.) |
|
|
60
|
+
| `flowframe_search_political_mentions` | Find mentions of a keyword in political speech transcripts |
|
|
61
|
+
| `flowframe_mention_frequency` | Time-series of how often a speaker mentions a keyword |
|
|
62
|
+
|
|
63
|
+
Every tool returns BOTH a human-readable text summary AND a `structuredContent` block containing the raw `{ data, meta }` envelope, so downstream agent steps and other MCP clients can consume the data programmatically.
|
|
64
|
+
|
|
65
|
+
## Attribution
|
|
66
|
+
|
|
67
|
+
Every tool response ends with a "Data from FlowFrame (https://flowframe.xyz)" line. **Free-tier API consumers must keep this attribution visible in any UI built on top of the API.** Paid tiers may suppress it. See <https://flowframe.xyz/api-docs#attribution> for the full policy.
|
|
68
|
+
|
|
69
|
+
## Rate limits
|
|
70
|
+
|
|
71
|
+
- Free tier: 20 requests / hour / key
|
|
72
|
+
- Paid tiers: 600+ / hour — see <https://flowframe.xyz/api-docs#pricing>
|
|
73
|
+
|
|
74
|
+
When you hit the limit, the tool returns a clear error message including how many seconds to wait.
|
|
75
|
+
|
|
76
|
+
## Configuration
|
|
77
|
+
|
|
78
|
+
| Env var | Default | Description |
|
|
79
|
+
|---|---|---|
|
|
80
|
+
| `FLOWFRAME_API_KEY` | *(required)* | Bearer token from `/account/api-keys` |
|
|
81
|
+
| `FLOWFRAME_API_BASE` | `https://flowframe.xyz` | Override for staging / self-hosted |
|
|
82
|
+
|
|
83
|
+
## Development
|
|
84
|
+
|
|
85
|
+
```bash
|
|
86
|
+
git clone <repo>
|
|
87
|
+
cd packages/mcp
|
|
88
|
+
npm install
|
|
89
|
+
npm run build
|
|
90
|
+
FLOWFRAME_API_KEY=flowframe_test_... node dist/index.js
|
|
91
|
+
```
|
|
92
|
+
|
|
93
|
+
The server speaks MCP over stdio — for ad-hoc testing, the [MCP Inspector](https://github.com/modelcontextprotocol/inspector) is the easiest way to exercise tools manually.
|
|
94
|
+
|
|
95
|
+
## License
|
|
96
|
+
|
|
97
|
+
MIT — see [LICENSE](./LICENSE).
|
package/dist/client.d.ts
ADDED
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Thin HTTP client for the FlowFrame /v1 API.
|
|
3
|
+
* Handles bearer auth, base URL, JSON parsing, structured error mapping,
|
|
4
|
+
* and one transparent retry on transient network failures.
|
|
5
|
+
*/
|
|
6
|
+
export interface BrandMeta {
|
|
7
|
+
source: string;
|
|
8
|
+
docs: string;
|
|
9
|
+
attribution: {
|
|
10
|
+
required: boolean;
|
|
11
|
+
label: string;
|
|
12
|
+
url: string;
|
|
13
|
+
terms?: string;
|
|
14
|
+
tier: string;
|
|
15
|
+
};
|
|
16
|
+
}
|
|
17
|
+
export interface Envelope<T> {
|
|
18
|
+
data: T;
|
|
19
|
+
meta: {
|
|
20
|
+
fetchedAt: string;
|
|
21
|
+
brand?: BrandMeta;
|
|
22
|
+
[k: string]: unknown;
|
|
23
|
+
};
|
|
24
|
+
}
|
|
25
|
+
export declare class FlowFrameApiError extends Error {
|
|
26
|
+
readonly status: number;
|
|
27
|
+
readonly code: string;
|
|
28
|
+
readonly retryAfterSeconds?: number | undefined;
|
|
29
|
+
constructor(status: number, code: string, message: string, retryAfterSeconds?: number | undefined);
|
|
30
|
+
}
|
|
31
|
+
export declare class FlowFrameClient {
|
|
32
|
+
private readonly baseUrl;
|
|
33
|
+
private readonly apiKey;
|
|
34
|
+
constructor(opts: {
|
|
35
|
+
apiKey: string;
|
|
36
|
+
baseUrl?: string;
|
|
37
|
+
});
|
|
38
|
+
get<T>(path: string, query?: Record<string, string | number | boolean | undefined | null>): Promise<Envelope<T>>;
|
|
39
|
+
private errorMessage;
|
|
40
|
+
}
|
package/dist/client.js
ADDED
|
@@ -0,0 +1,104 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Thin HTTP client for the FlowFrame /v1 API.
|
|
3
|
+
* Handles bearer auth, base URL, JSON parsing, structured error mapping,
|
|
4
|
+
* and one transparent retry on transient network failures.
|
|
5
|
+
*/
|
|
6
|
+
const DEFAULT_BASE_URL = "https://flowframe.xyz";
|
|
7
|
+
const USER_AGENT = "flowframe-mcp-server/0.1.0";
|
|
8
|
+
export class FlowFrameApiError extends Error {
|
|
9
|
+
status;
|
|
10
|
+
code;
|
|
11
|
+
retryAfterSeconds;
|
|
12
|
+
constructor(status, code, message, retryAfterSeconds) {
|
|
13
|
+
super(message);
|
|
14
|
+
this.status = status;
|
|
15
|
+
this.code = code;
|
|
16
|
+
this.retryAfterSeconds = retryAfterSeconds;
|
|
17
|
+
this.name = "FlowFrameApiError";
|
|
18
|
+
}
|
|
19
|
+
}
|
|
20
|
+
export class FlowFrameClient {
|
|
21
|
+
baseUrl;
|
|
22
|
+
apiKey;
|
|
23
|
+
constructor(opts) {
|
|
24
|
+
if (!opts.apiKey) {
|
|
25
|
+
throw new Error("FLOWFRAME_API_KEY is required. Generate one at https://flowframe.xyz/account/api-keys " +
|
|
26
|
+
"and add it to your MCP client config (env.FLOWFRAME_API_KEY).");
|
|
27
|
+
}
|
|
28
|
+
this.apiKey = opts.apiKey;
|
|
29
|
+
this.baseUrl = (opts.baseUrl ?? DEFAULT_BASE_URL).replace(/\/+$/, "");
|
|
30
|
+
}
|
|
31
|
+
async get(path, query) {
|
|
32
|
+
const url = new URL(`/v1${path}`, this.baseUrl);
|
|
33
|
+
if (query) {
|
|
34
|
+
for (const [k, v] of Object.entries(query)) {
|
|
35
|
+
if (v === undefined || v === null || v === "")
|
|
36
|
+
continue;
|
|
37
|
+
url.searchParams.set(k, String(v));
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
const doFetch = () => fetch(url.toString(), {
|
|
41
|
+
method: "GET",
|
|
42
|
+
headers: {
|
|
43
|
+
Authorization: `Bearer ${this.apiKey}`,
|
|
44
|
+
Accept: "application/json",
|
|
45
|
+
"User-Agent": USER_AGENT,
|
|
46
|
+
},
|
|
47
|
+
});
|
|
48
|
+
let res;
|
|
49
|
+
try {
|
|
50
|
+
res = await doFetch();
|
|
51
|
+
}
|
|
52
|
+
catch (err) {
|
|
53
|
+
// One retry on transient network failures (DNS hiccup, ECONNRESET, etc.)
|
|
54
|
+
await new Promise((r) => setTimeout(r, 500));
|
|
55
|
+
try {
|
|
56
|
+
res = await doFetch();
|
|
57
|
+
}
|
|
58
|
+
catch (err2) {
|
|
59
|
+
throw new FlowFrameApiError(0, "network_error", `Network error contacting ${url.host}: ${err2.message}`);
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
const text = await res.text();
|
|
63
|
+
let body = null;
|
|
64
|
+
if (text) {
|
|
65
|
+
try {
|
|
66
|
+
body = JSON.parse(text);
|
|
67
|
+
}
|
|
68
|
+
catch {
|
|
69
|
+
// Non-JSON response — surface raw text in the error.
|
|
70
|
+
throw new FlowFrameApiError(res.status, "invalid_response", `Non-JSON response from FlowFrame API (HTTP ${res.status}): ${text.slice(0, 200)}`);
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
if (!res.ok) {
|
|
74
|
+
const code = body?.error ?? "internal_error";
|
|
75
|
+
const retryAfter = typeof body?.retryAfterSeconds === "number" ? body.retryAfterSeconds : undefined;
|
|
76
|
+
throw new FlowFrameApiError(res.status, code, this.errorMessage(res.status, code, body), retryAfter);
|
|
77
|
+
}
|
|
78
|
+
return body;
|
|
79
|
+
}
|
|
80
|
+
errorMessage(status, code, body) {
|
|
81
|
+
switch (code) {
|
|
82
|
+
case "unauthorized":
|
|
83
|
+
return "FlowFrame API rejected the API key. Generate a new one at https://flowframe.xyz/account/api-keys and update FLOWFRAME_API_KEY in your MCP client config.";
|
|
84
|
+
case "forbidden":
|
|
85
|
+
return "This endpoint requires a paid FlowFrame tier. See https://flowframe.xyz/api-docs#pricing.";
|
|
86
|
+
case "rate_limit_exceeded": {
|
|
87
|
+
const wait = body?.retryAfterSeconds;
|
|
88
|
+
const waitStr = typeof wait === "number" ? ` Retry in ${wait} seconds.` : "";
|
|
89
|
+
return `FlowFrame rate limit hit.${waitStr} Your current key appears to be on the free tier (20 req/hour). See https://flowframe.xyz/api-docs#pricing for higher limits.`;
|
|
90
|
+
}
|
|
91
|
+
case "not_found":
|
|
92
|
+
return "Requested resource not found.";
|
|
93
|
+
case "validation_error": {
|
|
94
|
+
const msgs = Array.isArray(body?.details)
|
|
95
|
+
? body.details.map((d) => d?.message).filter(Boolean).join("; ")
|
|
96
|
+
: null;
|
|
97
|
+
return msgs ? `Invalid request: ${msgs}` : "Invalid request parameters.";
|
|
98
|
+
}
|
|
99
|
+
default:
|
|
100
|
+
return `FlowFrame API error (HTTP ${status}, code=${code}).`;
|
|
101
|
+
}
|
|
102
|
+
}
|
|
103
|
+
}
|
|
104
|
+
//# sourceMappingURL=client.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"client.js","sourceRoot":"","sources":["../src/client.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Convert FlowFrame /v1 envelopes into MCP tool results.
|
|
3
|
+
*
|
|
4
|
+
* Every result returns BOTH:
|
|
5
|
+
* - a human-readable text block (Claude reasons over labeled prose well),
|
|
6
|
+
* - a `structuredContent` block (the raw envelope) so other MCP clients and
|
|
7
|
+
* downstream agent steps can consume the data programmatically.
|
|
8
|
+
*
|
|
9
|
+
* Attribution is appended unconditionally to every response. If the envelope
|
|
10
|
+
* also carries a `meta.brand.attribution` block from the API, we use its label
|
|
11
|
+
* and URL; otherwise we fall back to a generic FlowFrame line.
|
|
12
|
+
*/
|
|
13
|
+
import type { Envelope, FlowFrameApiError } from "./client.js";
|
|
14
|
+
export interface ToolResult {
|
|
15
|
+
content: {
|
|
16
|
+
type: "text";
|
|
17
|
+
text: string;
|
|
18
|
+
}[];
|
|
19
|
+
structuredContent?: Record<string, unknown>;
|
|
20
|
+
isError?: true;
|
|
21
|
+
[key: string]: unknown;
|
|
22
|
+
}
|
|
23
|
+
interface FormatOptions {
|
|
24
|
+
/**
|
|
25
|
+
* Extra attribution line appended after the FlowFrame line.
|
|
26
|
+
* Use for endpoints that wrap third-party data (e.g., predicting.top).
|
|
27
|
+
*/
|
|
28
|
+
extraAttribution?: string;
|
|
29
|
+
}
|
|
30
|
+
export declare function formatEnvelope<T>(title: string, envelope: Envelope<T>, body: string, options?: FormatOptions): ToolResult;
|
|
31
|
+
/**
|
|
32
|
+
* Wrap a non-envelope payload (e.g. a synthetic ping result) the same way:
|
|
33
|
+
* prose + structured content + attribution.
|
|
34
|
+
*/
|
|
35
|
+
export declare function formatPlain(title: string, body: string, structured: Record<string, unknown>): ToolResult;
|
|
36
|
+
export declare function formatError(err: FlowFrameApiError | Error): ToolResult;
|
|
37
|
+
export declare function fmtPct(n: number | null | undefined, digits?: number): string;
|
|
38
|
+
export declare function fmtUsd(n: number | null | undefined): string;
|
|
39
|
+
export declare function fmtPrice(n: number | null | undefined): string;
|
|
40
|
+
export {};
|
|
@@ -0,0 +1,84 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Convert FlowFrame /v1 envelopes into MCP tool results.
|
|
3
|
+
*
|
|
4
|
+
* Every result returns BOTH:
|
|
5
|
+
* - a human-readable text block (Claude reasons over labeled prose well),
|
|
6
|
+
* - a `structuredContent` block (the raw envelope) so other MCP clients and
|
|
7
|
+
* downstream agent steps can consume the data programmatically.
|
|
8
|
+
*
|
|
9
|
+
* Attribution is appended unconditionally to every response. If the envelope
|
|
10
|
+
* also carries a `meta.brand.attribution` block from the API, we use its label
|
|
11
|
+
* and URL; otherwise we fall back to a generic FlowFrame line.
|
|
12
|
+
*/
|
|
13
|
+
export function formatEnvelope(title, envelope, body, options = {}) {
|
|
14
|
+
const parts = [`${title}\n`, body.trim()];
|
|
15
|
+
const brand = envelope.meta?.brand;
|
|
16
|
+
const label = brand?.attribution?.label ?? "Data from FlowFrame";
|
|
17
|
+
const url = brand?.attribution?.url ?? "https://flowframe.xyz";
|
|
18
|
+
parts.push(`\n— ${label} (${url})`);
|
|
19
|
+
if (options.extraAttribution) {
|
|
20
|
+
parts.push(options.extraAttribution);
|
|
21
|
+
}
|
|
22
|
+
return {
|
|
23
|
+
content: [{ type: "text", text: parts.join("\n") }],
|
|
24
|
+
structuredContent: {
|
|
25
|
+
data: envelope.data,
|
|
26
|
+
meta: envelope.meta,
|
|
27
|
+
},
|
|
28
|
+
};
|
|
29
|
+
}
|
|
30
|
+
/**
|
|
31
|
+
* Wrap a non-envelope payload (e.g. a synthetic ping result) the same way:
|
|
32
|
+
* prose + structured content + attribution.
|
|
33
|
+
*/
|
|
34
|
+
export function formatPlain(title, body, structured) {
|
|
35
|
+
return {
|
|
36
|
+
content: [
|
|
37
|
+
{
|
|
38
|
+
type: "text",
|
|
39
|
+
text: `${title}\n\n${body.trim()}\n\n— Data from FlowFrame (https://flowframe.xyz)`,
|
|
40
|
+
},
|
|
41
|
+
],
|
|
42
|
+
structuredContent: structured,
|
|
43
|
+
};
|
|
44
|
+
}
|
|
45
|
+
export function formatError(err) {
|
|
46
|
+
const anyErr = err;
|
|
47
|
+
return {
|
|
48
|
+
isError: true,
|
|
49
|
+
content: [{ type: "text", text: err.message }],
|
|
50
|
+
structuredContent: {
|
|
51
|
+
error: {
|
|
52
|
+
message: err.message,
|
|
53
|
+
code: anyErr.code ?? "internal_error",
|
|
54
|
+
status: anyErr.status ?? 0,
|
|
55
|
+
...(typeof anyErr.retryAfterSeconds === "number"
|
|
56
|
+
? { retryAfterSeconds: anyErr.retryAfterSeconds }
|
|
57
|
+
: {}),
|
|
58
|
+
},
|
|
59
|
+
},
|
|
60
|
+
};
|
|
61
|
+
}
|
|
62
|
+
export function fmtPct(n, digits = 1) {
|
|
63
|
+
if (n === null || n === undefined || !isFinite(n))
|
|
64
|
+
return "n/a";
|
|
65
|
+
return `${n >= 0 ? "+" : ""}${n.toFixed(digits)}%`;
|
|
66
|
+
}
|
|
67
|
+
export function fmtUsd(n) {
|
|
68
|
+
if (n === null || n === undefined || !isFinite(n))
|
|
69
|
+
return "n/a";
|
|
70
|
+
if (Math.abs(n) >= 1e9)
|
|
71
|
+
return `$${(n / 1e9).toFixed(2)}B`;
|
|
72
|
+
if (Math.abs(n) >= 1e6)
|
|
73
|
+
return `$${(n / 1e6).toFixed(2)}M`;
|
|
74
|
+
if (Math.abs(n) >= 1e3)
|
|
75
|
+
return `$${(n / 1e3).toFixed(1)}K`;
|
|
76
|
+
return `$${n.toFixed(0)}`;
|
|
77
|
+
}
|
|
78
|
+
export function fmtPrice(n) {
|
|
79
|
+
if (n === null || n === undefined || !isFinite(n))
|
|
80
|
+
return "n/a";
|
|
81
|
+
// Polymarket prices are 0..1 probabilities — show as percentage.
|
|
82
|
+
return `${(n * 100).toFixed(1)}%`;
|
|
83
|
+
}
|
|
84
|
+
//# sourceMappingURL=formatter.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"formatter.js","sourceRoot":"","sources":["../src/formatter.ts"],"names":[],"mappings":"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"}
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
/**
|
|
3
|
+
* FlowFrame MCP Server
|
|
4
|
+
*
|
|
5
|
+
* Exposes the FlowFrame /v1 prediction-market intelligence API as Model
|
|
6
|
+
* Context Protocol tools so Claude (Desktop, Code, etc.) can call them
|
|
7
|
+
* directly during a conversation.
|
|
8
|
+
*
|
|
9
|
+
* Transport: stdio. Configure in Claude Desktop via:
|
|
10
|
+
*
|
|
11
|
+
* {
|
|
12
|
+
* "mcpServers": {
|
|
13
|
+
* "flowframe": {
|
|
14
|
+
* "command": "npx",
|
|
15
|
+
* "args": ["-y", "@flowframe22/mcp-server"],
|
|
16
|
+
* "env": { "FLOWFRAME_API_KEY": "flowframe_live_..." }
|
|
17
|
+
* }
|
|
18
|
+
* }
|
|
19
|
+
* }
|
|
20
|
+
*
|
|
21
|
+
* Get a free API key at https://flowframe.xyz/account/api-keys
|
|
22
|
+
*/
|
|
23
|
+
export {};
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
/**
|
|
3
|
+
* FlowFrame MCP Server
|
|
4
|
+
*
|
|
5
|
+
* Exposes the FlowFrame /v1 prediction-market intelligence API as Model
|
|
6
|
+
* Context Protocol tools so Claude (Desktop, Code, etc.) can call them
|
|
7
|
+
* directly during a conversation.
|
|
8
|
+
*
|
|
9
|
+
* Transport: stdio. Configure in Claude Desktop via:
|
|
10
|
+
*
|
|
11
|
+
* {
|
|
12
|
+
* "mcpServers": {
|
|
13
|
+
* "flowframe": {
|
|
14
|
+
* "command": "npx",
|
|
15
|
+
* "args": ["-y", "@flowframe22/mcp-server"],
|
|
16
|
+
* "env": { "FLOWFRAME_API_KEY": "flowframe_live_..." }
|
|
17
|
+
* }
|
|
18
|
+
* }
|
|
19
|
+
* }
|
|
20
|
+
*
|
|
21
|
+
* Get a free API key at https://flowframe.xyz/account/api-keys
|
|
22
|
+
*/
|
|
23
|
+
import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
|
|
24
|
+
import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
|
|
25
|
+
import { FlowFrameClient } from "./client.js";
|
|
26
|
+
import { registerTools } from "./tools.js";
|
|
27
|
+
const SERVER_NAME = "flowframe";
|
|
28
|
+
const SERVER_VERSION = "0.1.0";
|
|
29
|
+
async function main() {
|
|
30
|
+
const apiKey = process.env.FLOWFRAME_API_KEY;
|
|
31
|
+
const baseUrl = process.env.FLOWFRAME_API_BASE;
|
|
32
|
+
if (!apiKey) {
|
|
33
|
+
// Write to stderr so MCP clients surface this in their server logs.
|
|
34
|
+
// Stdout is reserved for the MCP protocol — never log there.
|
|
35
|
+
process.stderr.write("[flowframe-mcp] FLOWFRAME_API_KEY environment variable is required.\n" +
|
|
36
|
+
"[flowframe-mcp] Generate a free API key at https://flowframe.xyz/account/api-keys\n" +
|
|
37
|
+
"[flowframe-mcp] then add it to your MCP client config under env.FLOWFRAME_API_KEY.\n");
|
|
38
|
+
process.exit(1);
|
|
39
|
+
}
|
|
40
|
+
const client = new FlowFrameClient({ apiKey, baseUrl });
|
|
41
|
+
const server = new McpServer({
|
|
42
|
+
name: SERVER_NAME,
|
|
43
|
+
version: SERVER_VERSION,
|
|
44
|
+
});
|
|
45
|
+
registerTools(server, client);
|
|
46
|
+
const transport = new StdioServerTransport();
|
|
47
|
+
await server.connect(transport);
|
|
48
|
+
process.stderr.write(`[flowframe-mcp] Server v${SERVER_VERSION} ready (base=${baseUrl ?? "https://flowframe.xyz"}).\n`);
|
|
49
|
+
}
|
|
50
|
+
main().catch((err) => {
|
|
51
|
+
process.stderr.write(`[flowframe-mcp] Fatal error: ${err.stack ?? err}\n`);
|
|
52
|
+
process.exit(1);
|
|
53
|
+
});
|
|
54
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":";AACA;;;;;;;;;;;;;;;;;;;;GAoBG;AAEH,OAAO,EAAE,SAAS,EAAE,MAAM,yCAAyC,CAAC;AACpE,OAAO,EAAE,oBAAoB,EAAE,MAAM,2CAA2C,CAAC;AACjF,OAAO,EAAE,eAAe,EAAE,MAAM,aAAa,CAAC;AAC9C,OAAO,EAAE,aAAa,EAAE,MAAM,YAAY,CAAC;AAE3C,MAAM,WAAW,GAAG,WAAW,CAAC;AAChC,MAAM,cAAc,GAAG,OAAO,CAAC;AAE/B,KAAK,UAAU,IAAI;IACjB,MAAM,MAAM,GAAG,OAAO,CAAC,GAAG,CAAC,iBAAiB,CAAC;IAC7C,MAAM,OAAO,GAAG,OAAO,CAAC,GAAG,CAAC,kBAAkB,CAAC;IAE/C,IAAI,CAAC,MAAM,EAAE,CAAC;QACZ,oEAAoE;QACpE,6DAA6D;QAC7D,OAAO,CAAC,MAAM,CAAC,KAAK,CAClB,uEAAuE;YACrE,qFAAqF;YACrF,sFAAsF,CACzF,CAAC;QACF,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;IAClB,CAAC;IAED,MAAM,MAAM,GAAG,IAAI,eAAe,CAAC,EAAE,MAAM,EAAE,OAAO,EAAE,CAAC,CAAC;IACxD,MAAM,MAAM,GAAG,IAAI,SAAS,CAAC;QAC3B,IAAI,EAAE,WAAW;QACjB,OAAO,EAAE,cAAc;KACxB,CAAC,CAAC;IAEH,aAAa,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IAE9B,MAAM,SAAS,GAAG,IAAI,oBAAoB,EAAE,CAAC;IAC7C,MAAM,MAAM,CAAC,OAAO,CAAC,SAAS,CAAC,CAAC;IAEhC,OAAO,CAAC,MAAM,CAAC,KAAK,CAClB,2BAA2B,cAAc,gBAAgB,OAAO,IAAI,uBAAuB,MAAM,CAClG,CAAC;AACJ,CAAC;AAED,IAAI,EAAE,CAAC,KAAK,CAAC,CAAC,GAAG,EAAE,EAAE;IACnB,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,gCAAiC,GAAa,CAAC,KAAK,IAAI,GAAG,IAAI,CAAC,CAAC;IACtF,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;AAClB,CAAC,CAAC,CAAC"}
|
package/dist/tools.d.ts
ADDED
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Tool registrations for the FlowFrame MCP server.
|
|
3
|
+
*
|
|
4
|
+
* Each tool maps 1:1 to a /v1/* endpoint. Descriptions are written for the
|
|
5
|
+
* model — they explain WHEN to call the tool, WHAT it returns, and WHAT it
|
|
6
|
+
* does NOT do. Keeping these tight is the difference between a useful MCP
|
|
7
|
+
* server and one Claude ignores.
|
|
8
|
+
*/
|
|
9
|
+
import type { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
|
|
10
|
+
import { FlowFrameClient } from "./client.js";
|
|
11
|
+
export declare function registerTools(server: McpServer, client: FlowFrameClient): void;
|
package/dist/tools.js
ADDED
|
@@ -0,0 +1,418 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Tool registrations for the FlowFrame MCP server.
|
|
3
|
+
*
|
|
4
|
+
* Each tool maps 1:1 to a /v1/* endpoint. Descriptions are written for the
|
|
5
|
+
* model — they explain WHEN to call the tool, WHAT it returns, and WHAT it
|
|
6
|
+
* does NOT do. Keeping these tight is the difference between a useful MCP
|
|
7
|
+
* server and one Claude ignores.
|
|
8
|
+
*/
|
|
9
|
+
import { z } from "zod";
|
|
10
|
+
import { formatEnvelope, formatError, fmtPct, fmtPrice, fmtUsd } from "./formatter.js";
|
|
11
|
+
const SPEAKER_SLUGS = [
|
|
12
|
+
"donald-trump",
|
|
13
|
+
"jd-vance",
|
|
14
|
+
"karoline-leavitt",
|
|
15
|
+
"pete-hegseth",
|
|
16
|
+
"marco-rubio",
|
|
17
|
+
"jerome-powell",
|
|
18
|
+
];
|
|
19
|
+
const WindowEnum = z.enum(["1h", "4h", "12h", "24h"]);
|
|
20
|
+
const DirectionEnum = z.enum(["up", "down", "both"]);
|
|
21
|
+
export function registerTools(server, client) {
|
|
22
|
+
// ─────────────────────────────────────────────────────────────────────────
|
|
23
|
+
// Ping — install/health check
|
|
24
|
+
// ─────────────────────────────────────────────────────────────────────────
|
|
25
|
+
server.tool("flowframe_ping", "Health check for the FlowFrame MCP server. Confirms that FLOWFRAME_API_KEY is " +
|
|
26
|
+
"configured correctly and that the FlowFrame API is reachable. Returns the key id " +
|
|
27
|
+
"and tier on success. Use this first if any other FlowFrame tool is failing.", {}, async () => {
|
|
28
|
+
try {
|
|
29
|
+
const env = await client.get("/_ping");
|
|
30
|
+
const d = env.data;
|
|
31
|
+
const body = [
|
|
32
|
+
`OK — FlowFrame API is reachable.`,
|
|
33
|
+
`Key id: ${d.keyId}`,
|
|
34
|
+
`Tier: ${d.tier}`,
|
|
35
|
+
].join("\n");
|
|
36
|
+
return formatEnvelope("FlowFrame ping:", env, body);
|
|
37
|
+
}
|
|
38
|
+
catch (err) {
|
|
39
|
+
return formatError(err);
|
|
40
|
+
}
|
|
41
|
+
});
|
|
42
|
+
// ─────────────────────────────────────────────────────────────────────────
|
|
43
|
+
// Pulse — FlowFrame's own market analysis feed
|
|
44
|
+
// ─────────────────────────────────────────────────────────────────────────
|
|
45
|
+
server.tool("flowframe_list_pulse", "List recent FlowFrame Pulse items — short-form analysis written by FlowFrame about " +
|
|
46
|
+
"specific Polymarket and Kalshi markets. Use when the user asks 'what's new on FlowFrame', " +
|
|
47
|
+
"'what is FlowFrame saying about prediction markets lately', or wants original analysis " +
|
|
48
|
+
"rather than raw market data. Returns title, source, publish date, content, the underlying " +
|
|
49
|
+
"Polymarket conditionId (if any), and a permalink. Sorted newest first. " +
|
|
50
|
+
"Do NOT use for market price data — use flowframe_polymarket_movers for that.", {
|
|
51
|
+
limit: z
|
|
52
|
+
.number()
|
|
53
|
+
.int()
|
|
54
|
+
.min(1)
|
|
55
|
+
.max(50)
|
|
56
|
+
.optional()
|
|
57
|
+
.describe("Number of items to return (default 10, max 50)."),
|
|
58
|
+
source: z
|
|
59
|
+
.string()
|
|
60
|
+
.optional()
|
|
61
|
+
.describe("Filter by source name (e.g., 'Polymarket', 'Kalshi'). Optional."),
|
|
62
|
+
since: z
|
|
63
|
+
.string()
|
|
64
|
+
.optional()
|
|
65
|
+
.describe("ISO 8601 timestamp; only return items published after this time."),
|
|
66
|
+
}, async ({ limit, source, since }) => {
|
|
67
|
+
try {
|
|
68
|
+
const env = await client.get("/pulse", { limit: limit ?? 10, source, since });
|
|
69
|
+
if (env.data.length === 0) {
|
|
70
|
+
return formatEnvelope("No FlowFrame Pulse items match those filters.", env, "");
|
|
71
|
+
}
|
|
72
|
+
const body = env.data
|
|
73
|
+
.map((item, i) => {
|
|
74
|
+
const date = new Date(item.publishedAt).toISOString().slice(0, 10);
|
|
75
|
+
const snippet = (item.content ?? "").replace(/\s+/g, " ").trim().slice(0, 280);
|
|
76
|
+
return [
|
|
77
|
+
`${i + 1}. ${item.subject}`,
|
|
78
|
+
` Published: ${date} | Source: ${item.source}${item.conditionId ? ` | conditionId: ${item.conditionId}` : ""}`,
|
|
79
|
+
` ${snippet}${snippet.length === 280 ? "…" : ""}`,
|
|
80
|
+
` ${item.permalink}`,
|
|
81
|
+
].join("\n");
|
|
82
|
+
})
|
|
83
|
+
.join("\n\n");
|
|
84
|
+
return formatEnvelope(`FlowFrame Pulse — ${env.data.length} most recent item(s):`, env, body);
|
|
85
|
+
}
|
|
86
|
+
catch (err) {
|
|
87
|
+
return formatError(err);
|
|
88
|
+
}
|
|
89
|
+
});
|
|
90
|
+
server.tool("flowframe_get_pulse_item", "Fetch a single FlowFrame Pulse item by its slug or uuid. Use after flowframe_list_pulse " +
|
|
91
|
+
"when the user says 'open that one', 'show me the full text', or 'summarize the second " +
|
|
92
|
+
"item' — the slug from the list result goes here. Returns the full content (not truncated), " +
|
|
93
|
+
"title, source, publish date, conditionId, and permalink.", {
|
|
94
|
+
identifier: z
|
|
95
|
+
.string()
|
|
96
|
+
.min(1)
|
|
97
|
+
.describe("The Pulse item slug (preferred — looks like 'trump-china-tariff-2026-04-01') or its uuid."),
|
|
98
|
+
}, async ({ identifier }) => {
|
|
99
|
+
try {
|
|
100
|
+
const env = await client.get(`/pulse/${encodeURIComponent(identifier)}`);
|
|
101
|
+
const item = env.data;
|
|
102
|
+
const date = new Date(item.publishedAt).toISOString().slice(0, 10);
|
|
103
|
+
const body = [
|
|
104
|
+
`${item.subject}`,
|
|
105
|
+
`Published: ${date} | Source: ${item.source}${item.conditionId ? ` | conditionId: ${item.conditionId}` : ""}`,
|
|
106
|
+
`Permalink: ${item.permalink}`,
|
|
107
|
+
``,
|
|
108
|
+
(item.content ?? "").trim(),
|
|
109
|
+
].join("\n");
|
|
110
|
+
return formatEnvelope("FlowFrame Pulse item:", env, body);
|
|
111
|
+
}
|
|
112
|
+
catch (err) {
|
|
113
|
+
return formatError(err);
|
|
114
|
+
}
|
|
115
|
+
});
|
|
116
|
+
server.tool("flowframe_get_pulse_for_market", "Get all FlowFrame Pulse items written about a specific Polymarket market, identified by " +
|
|
117
|
+
"its conditionId (a 0x-prefixed hex string from polymarket.com URLs or any Polymarket API). " +
|
|
118
|
+
"Use when the user references a specific market and asks 'what does FlowFrame say about this'. " +
|
|
119
|
+
"Returns up to 100 items, newest first. Returns an empty list if FlowFrame hasn't covered " +
|
|
120
|
+
"that market or if it's a Kalshi-only market (Kalshi markets aren't matched by conditionId).", {
|
|
121
|
+
conditionId: z
|
|
122
|
+
.string()
|
|
123
|
+
.min(3)
|
|
124
|
+
.describe("Polymarket conditionId, e.g. '0x1234...'. Required."),
|
|
125
|
+
}, async ({ conditionId }) => {
|
|
126
|
+
try {
|
|
127
|
+
const env = await client.get(`/pulse/by-market/${encodeURIComponent(conditionId)}`);
|
|
128
|
+
if (env.data.length === 0) {
|
|
129
|
+
return formatEnvelope(`No FlowFrame Pulse coverage for market ${conditionId}.`, env, "");
|
|
130
|
+
}
|
|
131
|
+
const body = env.data
|
|
132
|
+
.map((item, i) => {
|
|
133
|
+
const date = new Date(item.publishedAt).toISOString().slice(0, 10);
|
|
134
|
+
const snippet = (item.content ?? "").replace(/\s+/g, " ").trim().slice(0, 400);
|
|
135
|
+
return `${i + 1}. ${item.subject} (${date})\n ${snippet}\n ${item.permalink}`;
|
|
136
|
+
})
|
|
137
|
+
.join("\n\n");
|
|
138
|
+
return formatEnvelope(`FlowFrame Pulse coverage for market ${conditionId} (${env.data.length} item(s)):`, env, body);
|
|
139
|
+
}
|
|
140
|
+
catch (err) {
|
|
141
|
+
return formatError(err);
|
|
142
|
+
}
|
|
143
|
+
});
|
|
144
|
+
// ─────────────────────────────────────────────────────────────────────────
|
|
145
|
+
// Movers — Polymarket / Kalshi
|
|
146
|
+
// ─────────────────────────────────────────────────────────────────────────
|
|
147
|
+
server.tool("flowframe_polymarket_movers", "Top Polymarket markets by recent price change. Use when the user asks 'what's moving on " +
|
|
148
|
+
"Polymarket', 'biggest movers in the last X hours', or wants to find markets where " +
|
|
149
|
+
"consensus has shifted. Returns market title, current price, price at start of window, " +
|
|
150
|
+
"delta in percentage points, 24h volume, and the polymarket.com URL. Sorted by " +
|
|
151
|
+
"abs(delta) descending.", {
|
|
152
|
+
window: WindowEnum.optional().describe("Lookback window: 1h, 4h, 12h, or 24h. Default 24h."),
|
|
153
|
+
direction: DirectionEnum.optional().describe("'up' = only markets that moved up, 'down' = only down, 'both' = either direction (default)."),
|
|
154
|
+
limit: z
|
|
155
|
+
.number()
|
|
156
|
+
.int()
|
|
157
|
+
.min(1)
|
|
158
|
+
.max(50)
|
|
159
|
+
.optional()
|
|
160
|
+
.describe("Number of markets to return (default 10, max 50)."),
|
|
161
|
+
}, async ({ window, direction, limit }) => {
|
|
162
|
+
try {
|
|
163
|
+
const env = await client.get("/movers/polymarket", {
|
|
164
|
+
window: window ?? "24h",
|
|
165
|
+
direction: direction ?? "both",
|
|
166
|
+
limit: limit ?? 10,
|
|
167
|
+
});
|
|
168
|
+
if (env.data.length === 0) {
|
|
169
|
+
return formatEnvelope("No Polymarket movers match those filters.", env, "");
|
|
170
|
+
}
|
|
171
|
+
const body = env.data
|
|
172
|
+
.map((m, i) => {
|
|
173
|
+
return [
|
|
174
|
+
`${i + 1}. ${m.marketTitle ?? "(untitled)"}`,
|
|
175
|
+
` ${fmtPrice(m.priceFrom)} → ${fmtPrice(m.currentPrice)} (${fmtPct(m.deltaPct)}, vol24h ${fmtUsd(m.volume24h)})`,
|
|
176
|
+
` ${m.polymarketUrl ?? ""}`,
|
|
177
|
+
].join("\n");
|
|
178
|
+
})
|
|
179
|
+
.join("\n\n");
|
|
180
|
+
return formatEnvelope(`Top ${env.data.length} Polymarket movers (${env.meta.window ?? window ?? "24h"} window):`, env, body);
|
|
181
|
+
}
|
|
182
|
+
catch (err) {
|
|
183
|
+
return formatError(err);
|
|
184
|
+
}
|
|
185
|
+
});
|
|
186
|
+
server.tool("flowframe_kalshi_movers", "Top Kalshi markets by recent price change. Use when the user asks 'what's moving on " +
|
|
187
|
+
"Kalshi'. Returns market title, current price, delta, volume, and Kalshi URL. " +
|
|
188
|
+
"Use flowframe_polymarket_movers for Polymarket — Kalshi and Polymarket are separate venues " +
|
|
189
|
+
"with separate markets.", {
|
|
190
|
+
window: WindowEnum.optional().describe("Lookback window. Default 24h."),
|
|
191
|
+
direction: DirectionEnum.optional().describe("Direction filter. Default 'both'."),
|
|
192
|
+
limit: z.number().int().min(1).max(50).optional().describe("Default 10, max 50."),
|
|
193
|
+
}, async ({ window, direction, limit }) => {
|
|
194
|
+
try {
|
|
195
|
+
const env = await client.get("/movers/kalshi", {
|
|
196
|
+
window: window ?? "24h",
|
|
197
|
+
direction: direction ?? "both",
|
|
198
|
+
limit: limit ?? 10,
|
|
199
|
+
});
|
|
200
|
+
if (env.data.length === 0) {
|
|
201
|
+
return formatEnvelope("No Kalshi movers match those filters.", env, "");
|
|
202
|
+
}
|
|
203
|
+
// Kalshi prices are in cents (1..99). Convert to fraction for fmtPrice.
|
|
204
|
+
const centsToFrac = (n) => typeof n === "number" ? n / 100 : null;
|
|
205
|
+
const body = env.data
|
|
206
|
+
.map((m, i) => {
|
|
207
|
+
return [
|
|
208
|
+
`${i + 1}. ${m.title ?? m.eventTitle ?? "(untitled)"}`,
|
|
209
|
+
` ${fmtPrice(centsToFrac(m.previousPrice))} → ${fmtPrice(centsToFrac(m.currentPrice))} (${fmtPct(m.priceChangePercent)}, vol24h ${fmtUsd(m.volume24h)})`,
|
|
210
|
+
` ${m.kalshiUrl ?? ""}`,
|
|
211
|
+
].join("\n");
|
|
212
|
+
})
|
|
213
|
+
.join("\n\n");
|
|
214
|
+
const note = env.meta.windowNote ? ` ${env.meta.windowNote}` : "";
|
|
215
|
+
return formatEnvelope(`Top ${env.data.length} Kalshi movers (24h since previous_yes_bid reset).${note}`, env, body);
|
|
216
|
+
}
|
|
217
|
+
catch (err) {
|
|
218
|
+
return formatError(err);
|
|
219
|
+
}
|
|
220
|
+
});
|
|
221
|
+
// ─────────────────────────────────────────────────────────────────────────
|
|
222
|
+
// Smart Money Skew
|
|
223
|
+
// ─────────────────────────────────────────────────────────────────────────
|
|
224
|
+
server.tool("flowframe_smart_money_skew", "Find Polymarket markets where the top 30 most-profitable traders (last 30d, ranked by P&L " +
|
|
225
|
+
"from predicting.top) are positioned disproportionately on one side compared to the market " +
|
|
226
|
+
"price. Use this to find markets where 'smart money' disagrees with the consensus. " +
|
|
227
|
+
"Returns: market title, current market price, smart-money implied fair value, edge (in " +
|
|
228
|
+
"percentage points), composite skew score, and per-tier dollar positions (Sharp = top 10, " +
|
|
229
|
+
"Profitable = 11-20, Recreational = 21-30). Sorted by composite score descending. " +
|
|
230
|
+
"For a single market's full breakdown by conditionId, use flowframe_smart_money_skew_for_market.", {
|
|
231
|
+
limit: z
|
|
232
|
+
.number()
|
|
233
|
+
.int()
|
|
234
|
+
.min(1)
|
|
235
|
+
.max(50)
|
|
236
|
+
.optional()
|
|
237
|
+
.describe("Number of markets to return (default 10, max 50)."),
|
|
238
|
+
minScore: z
|
|
239
|
+
.number()
|
|
240
|
+
.optional()
|
|
241
|
+
.describe("Filter to markets with composite skew score ≥ this value. Optional."),
|
|
242
|
+
}, async ({ limit, minScore }) => {
|
|
243
|
+
try {
|
|
244
|
+
const env = await client.get("/smart-money/skew", {
|
|
245
|
+
limit: limit ?? 10,
|
|
246
|
+
minScore,
|
|
247
|
+
});
|
|
248
|
+
if (env.data.length === 0) {
|
|
249
|
+
return formatEnvelope("No smart-money skew signals match those filters.", env, "");
|
|
250
|
+
}
|
|
251
|
+
const body = env.data
|
|
252
|
+
.map((m, i) => {
|
|
253
|
+
return [
|
|
254
|
+
`${i + 1}. ${m.marketTitle ?? "(untitled)"} [conditionId: ${m.conditionId}]`,
|
|
255
|
+
` Market price ${fmtPrice(m.marketPrice)} | Smart-money fair value ${fmtPrice(m.impliedFairValue)} | Edge ${fmtPct(m.edgePct)}`,
|
|
256
|
+
` Composite skew score: ${typeof m.compositeSkewScore === "number" ? m.compositeSkewScore.toFixed(2) : "n/a"}`,
|
|
257
|
+
].join("\n");
|
|
258
|
+
})
|
|
259
|
+
.join("\n\n");
|
|
260
|
+
return formatEnvelope(`Top ${env.data.length} smart-money skew signal(s):`, env, body);
|
|
261
|
+
}
|
|
262
|
+
catch (err) {
|
|
263
|
+
return formatError(err);
|
|
264
|
+
}
|
|
265
|
+
});
|
|
266
|
+
server.tool("flowframe_smart_money_skew_for_market", "Get the full smart-money skew breakdown for a single Polymarket market by conditionId, " +
|
|
267
|
+
"including per-tier (Sharp / Profitable / Recreational) dollar positions and which side " +
|
|
268
|
+
"each tier is on. Use after flowframe_smart_money_skew when the user wants to drill into " +
|
|
269
|
+
"one specific market.", {
|
|
270
|
+
conditionId: z.string().min(3).describe("Polymarket conditionId. Required."),
|
|
271
|
+
}, async ({ conditionId }) => {
|
|
272
|
+
try {
|
|
273
|
+
const env = await client.get(`/smart-money/skew/${encodeURIComponent(conditionId)}`);
|
|
274
|
+
const m = env.data;
|
|
275
|
+
const tiers = m.tiers ?? {};
|
|
276
|
+
const tierLine = (name, t) => {
|
|
277
|
+
if (!t)
|
|
278
|
+
return ` - ${name}: no data`;
|
|
279
|
+
const yes = Number(t.yesDollars ?? 0);
|
|
280
|
+
const no = Number(t.noDollars ?? 0);
|
|
281
|
+
const total = yes + no;
|
|
282
|
+
if (total === 0)
|
|
283
|
+
return ` - ${name}: no positions`;
|
|
284
|
+
const side = yes >= no ? "YES" : "NO";
|
|
285
|
+
const dom = Math.max(yes, no);
|
|
286
|
+
const sharePct = (dom / total) * 100;
|
|
287
|
+
const skewStr = typeof t.skew === "number" ? `, skew ${t.skew.toFixed(2)}` : "";
|
|
288
|
+
return ` - ${name}: ${fmtUsd(dom)} on ${side} (${sharePct.toFixed(0)}% of tier capital${skewStr})`;
|
|
289
|
+
};
|
|
290
|
+
const body = [
|
|
291
|
+
`${m.marketTitle ?? "(untitled)"} [conditionId: ${m.conditionId}]`,
|
|
292
|
+
`Market price ${fmtPrice(m.marketPrice)} | Smart-money fair value ${fmtPrice(m.impliedFairValue)} | Edge ${fmtPct(m.edgePct)}`,
|
|
293
|
+
`Composite skew score: ${typeof m.compositeSkewScore === "number" ? m.compositeSkewScore.toFixed(2) : "n/a"}`,
|
|
294
|
+
"Tier breakdown:",
|
|
295
|
+
tierLine("Sharp (top 10)", tiers.sharp),
|
|
296
|
+
tierLine("Profitable (11-20)", tiers.profitable),
|
|
297
|
+
tierLine("Recreational (21-30)", tiers.recreational),
|
|
298
|
+
m.lastUpdated ? `Last updated: ${m.lastUpdated}` : "",
|
|
299
|
+
]
|
|
300
|
+
.filter(Boolean)
|
|
301
|
+
.join("\n");
|
|
302
|
+
return formatEnvelope("Smart-money skew detail:", env, body);
|
|
303
|
+
}
|
|
304
|
+
catch (err) {
|
|
305
|
+
return formatError(err);
|
|
306
|
+
}
|
|
307
|
+
});
|
|
308
|
+
// ─────────────────────────────────────────────────────────────────────────
|
|
309
|
+
// Mentions Hub — political speech transcripts
|
|
310
|
+
// ─────────────────────────────────────────────────────────────────────────
|
|
311
|
+
server.tool("flowframe_list_speakers", "List the political speakers (US politicians + Fed chair) whose public-domain transcripts " +
|
|
312
|
+
"are searchable via flowframe_search_political_mentions and flowframe_mention_frequency. " +
|
|
313
|
+
"Use when the user asks 'who can I search', 'which politicians are indexed', or before " +
|
|
314
|
+
"calling search/frequency tools to confirm the speaker slug. Returns slug (use this in " +
|
|
315
|
+
"other tools), display name, title, party, transcript count, and date range covered.", {}, async () => {
|
|
316
|
+
try {
|
|
317
|
+
const env = await client.get("/mentions/speakers");
|
|
318
|
+
const body = env.data
|
|
319
|
+
.map((s) => {
|
|
320
|
+
const range = s.earliestDate && s.latestDate
|
|
321
|
+
? ` (${s.earliestDate} → ${s.latestDate})`
|
|
322
|
+
: "";
|
|
323
|
+
return `- ${s.slug} — ${s.name}${s.title ? `, ${s.title}` : ""}${s.party ? ` (${s.party})` : ""} — ${s.transcriptCount} transcripts${range}`;
|
|
324
|
+
})
|
|
325
|
+
.join("\n");
|
|
326
|
+
return formatEnvelope("Indexed political speakers:", env, body);
|
|
327
|
+
}
|
|
328
|
+
catch (err) {
|
|
329
|
+
return formatError(err);
|
|
330
|
+
}
|
|
331
|
+
});
|
|
332
|
+
server.tool("flowframe_search_political_mentions", "Search transcripts of US political speeches and Fed press conferences for a keyword or " +
|
|
333
|
+
"phrase. Returns transcripts (newest first) with snippet excerpts showing the keyword in " +
|
|
334
|
+
"context. Use when the user asks 'when did X talk about Y', 'has Powell mentioned tariffs', " +
|
|
335
|
+
"or wants verbatim quotes. Each result includes the transcript title, date, source, event " +
|
|
336
|
+
"format (rally / press conference / interview / etc.), the number of times the keyword " +
|
|
337
|
+
"appears in that transcript, and up to several snippets. Call flowframe_list_speakers first " +
|
|
338
|
+
"if you don't know the available speaker slugs.", {
|
|
339
|
+
q: z
|
|
340
|
+
.string()
|
|
341
|
+
.min(2)
|
|
342
|
+
.max(80)
|
|
343
|
+
.describe("Keyword or short phrase to search for, 2-80 chars. Case-insensitive. Slashes are OK " +
|
|
344
|
+
"(e.g. 'us/china' matches 'US/China' and 'US-China')."),
|
|
345
|
+
speaker: z
|
|
346
|
+
.enum(SPEAKER_SLUGS)
|
|
347
|
+
.optional()
|
|
348
|
+
.describe("Restrict to one speaker slug. Omit to search across all indexed speakers. " +
|
|
349
|
+
`Allowed: ${SPEAKER_SLUGS.join(", ")}.`),
|
|
350
|
+
limit: z.number().int().min(1).max(50).optional().describe("Default 10, max 50."),
|
|
351
|
+
}, async ({ q, speaker, limit }) => {
|
|
352
|
+
try {
|
|
353
|
+
const env = await client.get("/mentions/search", {
|
|
354
|
+
q,
|
|
355
|
+
speaker,
|
|
356
|
+
limit: limit ?? 10,
|
|
357
|
+
});
|
|
358
|
+
const meta = env.meta;
|
|
359
|
+
if (env.data.length === 0) {
|
|
360
|
+
return formatEnvelope(`No matches for "${q}"${speaker ? ` by ${speaker}` : ""}.`, env, "");
|
|
361
|
+
}
|
|
362
|
+
const body = env.data
|
|
363
|
+
.map((r, i) => {
|
|
364
|
+
const snippets = (r.snippets ?? [])
|
|
365
|
+
.slice(0, 3)
|
|
366
|
+
.map((s) => ` "${s.trim()}"`)
|
|
367
|
+
.join("\n");
|
|
368
|
+
return [
|
|
369
|
+
`${i + 1}. ${r.speakerName} — ${r.title} (${r.date})`,
|
|
370
|
+
` Source: ${r.source}${r.eventFormat ? ` | Format: ${r.eventFormat}` : ""} | Mentions: ${r.mentionCount}`,
|
|
371
|
+
snippets,
|
|
372
|
+
r.url ? ` ${r.url}` : "",
|
|
373
|
+
]
|
|
374
|
+
.filter(Boolean)
|
|
375
|
+
.join("\n");
|
|
376
|
+
})
|
|
377
|
+
.join("\n\n");
|
|
378
|
+
const summary = `Found ${meta.totalMentions ?? "?"} mention(s) across ${meta.totalDocuments ?? env.data.length} transcript(s) for "${q}"${speaker ? ` by ${speaker}` : ""}. Showing ${env.data.length}:`;
|
|
379
|
+
return formatEnvelope(summary, env, body);
|
|
380
|
+
}
|
|
381
|
+
catch (err) {
|
|
382
|
+
return formatError(err);
|
|
383
|
+
}
|
|
384
|
+
});
|
|
385
|
+
server.tool("flowframe_mention_frequency", "Time-series of how often a keyword appears in a speaker's transcripts, grouped by day, " +
|
|
386
|
+
"week, month, or year. Use when the user asks 'how often does X mention Y over time', " +
|
|
387
|
+
"'is Trump talking about China more lately', etc. Returns periods with mention counts and " +
|
|
388
|
+
"transcript counts. If no speaker is given, aggregates across all indexed speakers.", {
|
|
389
|
+
q: z.string().min(2).max(80).describe("Keyword or phrase, 2-80 chars."),
|
|
390
|
+
speaker: z
|
|
391
|
+
.enum(SPEAKER_SLUGS)
|
|
392
|
+
.optional()
|
|
393
|
+
.describe(`Speaker slug. Allowed: ${SPEAKER_SLUGS.join(", ")}.`),
|
|
394
|
+
granularity: z
|
|
395
|
+
.enum(["day", "week", "month", "year"])
|
|
396
|
+
.optional()
|
|
397
|
+
.describe("Bucket size. Default 'month'."),
|
|
398
|
+
}, async ({ q, speaker, granularity }) => {
|
|
399
|
+
try {
|
|
400
|
+
const env = await client.get("/mentions/frequency", {
|
|
401
|
+
q,
|
|
402
|
+
speaker,
|
|
403
|
+
granularity: granularity ?? "month",
|
|
404
|
+
});
|
|
405
|
+
if (env.data.length === 0) {
|
|
406
|
+
return formatEnvelope(`No mentions of "${q}"${speaker ? ` by ${speaker}` : ""}.`, env, "");
|
|
407
|
+
}
|
|
408
|
+
const body = env.data
|
|
409
|
+
.map((row) => ` ${row.period}: ${row.mentionCount} mention(s) across ${row.transcriptCount} transcript(s)`)
|
|
410
|
+
.join("\n");
|
|
411
|
+
return formatEnvelope(`Mention frequency for "${q}"${speaker ? ` by ${speaker}` : ""} (${granularity ?? "month"}):`, env, body);
|
|
412
|
+
}
|
|
413
|
+
catch (err) {
|
|
414
|
+
return formatError(err);
|
|
415
|
+
}
|
|
416
|
+
});
|
|
417
|
+
}
|
|
418
|
+
//# sourceMappingURL=tools.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"tools.js","sourceRoot":"","sources":["../src/tools.ts"],"names":[],"mappings":"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"}
|
package/package.json
ADDED
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@flowframe22/mcp-server",
|
|
3
|
+
"version": "0.1.0",
|
|
4
|
+
"description": "Model Context Protocol server for FlowFrame — bring prediction-market intelligence (Polymarket movers, smart-money skew, FlowFrame Pulse, political mentions) into Claude and any MCP-compatible client.",
|
|
5
|
+
"license": "MIT",
|
|
6
|
+
"type": "module",
|
|
7
|
+
"bin": {
|
|
8
|
+
"flowframe-mcp-server": "dist/index.js"
|
|
9
|
+
},
|
|
10
|
+
"main": "dist/index.js",
|
|
11
|
+
"files": [
|
|
12
|
+
"dist",
|
|
13
|
+
"README.md",
|
|
14
|
+
"LICENSE"
|
|
15
|
+
],
|
|
16
|
+
"scripts": {
|
|
17
|
+
"build": "tsc",
|
|
18
|
+
"dev": "tsx src/index.ts",
|
|
19
|
+
"prepublishOnly": "npm run build"
|
|
20
|
+
},
|
|
21
|
+
"engines": {
|
|
22
|
+
"node": ">=18.0.0"
|
|
23
|
+
},
|
|
24
|
+
"keywords": [
|
|
25
|
+
"mcp",
|
|
26
|
+
"model-context-protocol",
|
|
27
|
+
"claude",
|
|
28
|
+
"anthropic",
|
|
29
|
+
"polymarket",
|
|
30
|
+
"kalshi",
|
|
31
|
+
"prediction-markets",
|
|
32
|
+
"flowframe"
|
|
33
|
+
],
|
|
34
|
+
"homepage": "https://flowframe.xyz/api-docs",
|
|
35
|
+
"repository": {
|
|
36
|
+
"type": "git",
|
|
37
|
+
"url": "https://github.com/flowframe/mcp-server"
|
|
38
|
+
},
|
|
39
|
+
"dependencies": {
|
|
40
|
+
"@modelcontextprotocol/sdk": "^1.0.4",
|
|
41
|
+
"zod": "^3.23.8"
|
|
42
|
+
},
|
|
43
|
+
"devDependencies": {
|
|
44
|
+
"@types/node": "^20.11.0",
|
|
45
|
+
"tsx": "^4.7.0",
|
|
46
|
+
"typescript": "^5.4.0"
|
|
47
|
+
}
|
|
48
|
+
}
|