modernity-mcp 1.0.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/README.md +108 -0
- package/dist/api-client.d.ts +2 -0
- package/dist/api-client.js +34 -0
- package/dist/config.d.ts +5 -0
- package/dist/config.js +24 -0
- package/dist/index.d.ts +2 -0
- package/dist/index.js +72 -0
- package/dist/resources.d.ts +12 -0
- package/dist/resources.js +46 -0
- package/dist/tools.d.ts +14 -0
- package/dist/tools.js +208 -0
- package/package.json +37 -0
package/README.md
ADDED
|
@@ -0,0 +1,108 @@
|
|
|
1
|
+
# modernity-mcp
|
|
2
|
+
|
|
3
|
+
MCP (Model Context Protocol) server for [Modernity](https://modernity.live) — connect live data to Cursor and Claude.
|
|
4
|
+
|
|
5
|
+
## Prerequisites
|
|
6
|
+
|
|
7
|
+
- **Node.js** 18 or newer
|
|
8
|
+
- **API key** from [modernity.live](https://modernity.live) (get one free, no credit card)
|
|
9
|
+
|
|
10
|
+
## Quick Start
|
|
11
|
+
|
|
12
|
+
```bash
|
|
13
|
+
# Verify your key works
|
|
14
|
+
npx -y modernity-mcp --key=YOUR_API_KEY --test
|
|
15
|
+
```
|
|
16
|
+
|
|
17
|
+
If you see `Success! API is online and your key is valid.`, you're ready to connect.
|
|
18
|
+
|
|
19
|
+
## Connect to Cursor
|
|
20
|
+
|
|
21
|
+
1. Open **Cursor Settings** (Cmd+Shift+J or Ctrl+Shift+J)
|
|
22
|
+
2. Go to **Features** → **MCP**
|
|
23
|
+
3. Click **+ Add New MCP Server**
|
|
24
|
+
4. Fill in:
|
|
25
|
+
- **Name:** Modernity
|
|
26
|
+
- **Type:** stdio
|
|
27
|
+
- **Command:** `npx`
|
|
28
|
+
- **Args:** `-y modernity-mcp --key=YOUR_API_KEY`
|
|
29
|
+
5. Set **MODERNITY_API_KEY** in env, or pass `--key=YOUR_API_KEY` in Args
|
|
30
|
+
6. Save. The dot turns green when connected.
|
|
31
|
+
|
|
32
|
+
## Connect to Claude Desktop
|
|
33
|
+
|
|
34
|
+
1. Open your Claude config file:
|
|
35
|
+
- **Mac:** `~/Library/Application Support/Claude/claude_desktop_config.json`
|
|
36
|
+
- **Windows:** `%APPDATA%\Claude\claude_desktop_config.json`
|
|
37
|
+
2. Add to the `mcpServers` block:
|
|
38
|
+
|
|
39
|
+
```json
|
|
40
|
+
{
|
|
41
|
+
"mcpServers": {
|
|
42
|
+
"modernity": {
|
|
43
|
+
"command": "npx",
|
|
44
|
+
"args": ["-y", "modernity-mcp"],
|
|
45
|
+
"env": {
|
|
46
|
+
"MODERNITY_API_KEY": "YOUR_API_KEY"
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
```
|
|
52
|
+
|
|
53
|
+
3. Restart Claude Desktop. Look for the plug icon.
|
|
54
|
+
|
|
55
|
+
## Authentication
|
|
56
|
+
|
|
57
|
+
Provide your API key in one of two ways:
|
|
58
|
+
|
|
59
|
+
- **Environment variable:** `MODERNITY_API_KEY=your_key`
|
|
60
|
+
- **CLI argument:** `--key=your_key`
|
|
61
|
+
|
|
62
|
+
The server exits immediately with an error if no key is provided.
|
|
63
|
+
|
|
64
|
+
## Tool Reference
|
|
65
|
+
|
|
66
|
+
| Tool | Description |
|
|
67
|
+
|------|-------------|
|
|
68
|
+
| `get_recent_data` | Fetch recent messages from the live stream. Optional: `limit`, `source`, `category` |
|
|
69
|
+
| `query_topic` | Search for a topic across all sources. Required: `topic`. Optional: `timeframe`, `limit`, `format` |
|
|
70
|
+
| `multi_schema_query` | Query across Vespa schemas (doc, ticker, news, geo_alert). Required: `query`. Optional: `schemas`, `timeframe`, `limit` |
|
|
71
|
+
| `analyze_topic` | AI-powered topic analysis with recommendations. Required: `topic` |
|
|
72
|
+
| `get_sources` | List all available data sources and categories |
|
|
73
|
+
| `get_stream_stats` | Get live stream health and statistics |
|
|
74
|
+
| `get_key_info` | Check API key tier, usage, and rate limits |
|
|
75
|
+
| `check_health` | Verify the API is online |
|
|
76
|
+
| `get_pricing` | Get all pricing tiers and features |
|
|
77
|
+
|
|
78
|
+
## Resources
|
|
79
|
+
|
|
80
|
+
- `modernity://health` — API health status
|
|
81
|
+
- `modernity://sources` — Available sources and categories
|
|
82
|
+
- `modernity://pricing` — Pricing tiers
|
|
83
|
+
|
|
84
|
+
## Example Prompts
|
|
85
|
+
|
|
86
|
+
- "Check the stream status"
|
|
87
|
+
- "Get the last 20 data points"
|
|
88
|
+
- "Query for Bitcoin developments"
|
|
89
|
+
- "What's my API key usage?"
|
|
90
|
+
- "List all data sources"
|
|
91
|
+
|
|
92
|
+
## Troubleshooting
|
|
93
|
+
|
|
94
|
+
| Issue | Fix |
|
|
95
|
+
|-------|-----|
|
|
96
|
+
| "MODERNITY_API_KEY... is required" | Add the key via env or `--key=` |
|
|
97
|
+
| "Your API key is invalid" | Regenerate at [modernity.live/dashboard](https://modernity.live/dashboard) |
|
|
98
|
+
| "Rate limit exceeded" | Wait before retrying; check tier limits |
|
|
99
|
+
| "Tool not found" | Restart Cursor/Claude after config changes |
|
|
100
|
+
| Connection fails | Run `npx -y modernity-mcp --key=YOUR_KEY --test` to isolate the issue |
|
|
101
|
+
|
|
102
|
+
## Publish to npm
|
|
103
|
+
|
|
104
|
+
```bash
|
|
105
|
+
cd mcp
|
|
106
|
+
npm login
|
|
107
|
+
npm publish --access public
|
|
108
|
+
```
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
+
};
|
|
5
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
+
exports.createApiClient = createApiClient;
|
|
7
|
+
const axios_1 = __importDefault(require("axios"));
|
|
8
|
+
function createApiClient(apiBase, apiKey) {
|
|
9
|
+
const client = axios_1.default.create({
|
|
10
|
+
baseURL: apiBase,
|
|
11
|
+
headers: {
|
|
12
|
+
Authorization: `Bearer ${apiKey}`,
|
|
13
|
+
"Content-Type": "application/json",
|
|
14
|
+
},
|
|
15
|
+
});
|
|
16
|
+
client.interceptors.response.use((res) => res, (err) => {
|
|
17
|
+
if (err.response?.status === 401) {
|
|
18
|
+
throw new Error("Your API key is invalid. Please check your config.");
|
|
19
|
+
}
|
|
20
|
+
if (err.response?.status === 403) {
|
|
21
|
+
throw new Error("Access denied. Your API key may not have permission for this operation.");
|
|
22
|
+
}
|
|
23
|
+
if (err.response?.status === 429) {
|
|
24
|
+
const retryAfter = err.response?.data?.retry_after_seconds;
|
|
25
|
+
const msg = retryAfter
|
|
26
|
+
? `Rate limit exceeded. Retry in ${Math.ceil(retryAfter)} seconds.`
|
|
27
|
+
: "Rate limit exceeded. Please wait before retrying.";
|
|
28
|
+
throw new Error(msg);
|
|
29
|
+
}
|
|
30
|
+
const detail = err.response?.data?.detail;
|
|
31
|
+
throw new Error(detail || err.message || "API request failed.");
|
|
32
|
+
});
|
|
33
|
+
return client;
|
|
34
|
+
}
|
package/dist/config.d.ts
ADDED
package/dist/config.js
ADDED
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.getConfig = getConfig;
|
|
4
|
+
exports.shouldRunTest = shouldRunTest;
|
|
5
|
+
const API_BASE = "https://api.modernity.live";
|
|
6
|
+
function getApiKey() {
|
|
7
|
+
const envKey = process.env.MODERNITY_API_KEY;
|
|
8
|
+
const argKey = process.argv.find((arg) => arg.startsWith("--key="))?.split("=")[1];
|
|
9
|
+
const key = envKey || argKey?.trim();
|
|
10
|
+
if (!key) {
|
|
11
|
+
console.error("Error: MODERNITY_API_KEY environment variable or --key= argument is required.");
|
|
12
|
+
process.exit(1);
|
|
13
|
+
}
|
|
14
|
+
return key;
|
|
15
|
+
}
|
|
16
|
+
function getConfig() {
|
|
17
|
+
return {
|
|
18
|
+
apiBase: API_BASE,
|
|
19
|
+
apiKey: getApiKey(),
|
|
20
|
+
};
|
|
21
|
+
}
|
|
22
|
+
function shouldRunTest() {
|
|
23
|
+
return process.argv.includes("--test");
|
|
24
|
+
}
|
package/dist/index.d.ts
ADDED
package/dist/index.js
ADDED
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
"use strict";
|
|
3
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
4
|
+
const index_js_1 = require("@modelcontextprotocol/sdk/server/index.js");
|
|
5
|
+
const stdio_js_1 = require("@modelcontextprotocol/sdk/server/stdio.js");
|
|
6
|
+
const types_js_1 = require("@modelcontextprotocol/sdk/types.js");
|
|
7
|
+
const config_js_1 = require("./config.js");
|
|
8
|
+
const api_client_js_1 = require("./api-client.js");
|
|
9
|
+
const tools_js_1 = require("./tools.js");
|
|
10
|
+
const resources_js_1 = require("./resources.js");
|
|
11
|
+
async function runTest() {
|
|
12
|
+
const { apiBase, apiKey } = (0, config_js_1.getConfig)();
|
|
13
|
+
const client = (0, api_client_js_1.createApiClient)(apiBase, apiKey);
|
|
14
|
+
try {
|
|
15
|
+
await client.get("/health");
|
|
16
|
+
await client.get("/v1/keys/info");
|
|
17
|
+
console.log("Success! API is online and your key is valid.");
|
|
18
|
+
process.exit(0);
|
|
19
|
+
}
|
|
20
|
+
catch (err) {
|
|
21
|
+
console.error("Error:", err instanceof Error ? err.message : err);
|
|
22
|
+
process.exit(1);
|
|
23
|
+
}
|
|
24
|
+
}
|
|
25
|
+
async function runServer() {
|
|
26
|
+
const { apiBase, apiKey } = (0, config_js_1.getConfig)();
|
|
27
|
+
const client = (0, api_client_js_1.createApiClient)(apiBase, apiKey);
|
|
28
|
+
const server = new index_js_1.Server({
|
|
29
|
+
name: "modernity-mcp",
|
|
30
|
+
version: "1.0.0",
|
|
31
|
+
}, {
|
|
32
|
+
capabilities: {
|
|
33
|
+
resources: {},
|
|
34
|
+
tools: {},
|
|
35
|
+
},
|
|
36
|
+
});
|
|
37
|
+
server.setRequestHandler(types_js_1.ListToolsRequestSchema, async () => ({
|
|
38
|
+
tools: (0, tools_js_1.getToolDefinitions)(),
|
|
39
|
+
}));
|
|
40
|
+
server.setRequestHandler(types_js_1.CallToolRequestSchema, async (request) => {
|
|
41
|
+
const { name, arguments: args } = request.params;
|
|
42
|
+
const result = await (0, tools_js_1.handleToolCall)(client, name, args ?? {});
|
|
43
|
+
return {
|
|
44
|
+
content: [{ type: "text", text: result.text }],
|
|
45
|
+
isError: result.isError,
|
|
46
|
+
};
|
|
47
|
+
});
|
|
48
|
+
server.setRequestHandler(types_js_1.ListResourcesRequestSchema, async () => ({
|
|
49
|
+
resources: resources_js_1.RESOURCES,
|
|
50
|
+
}));
|
|
51
|
+
server.setRequestHandler(types_js_1.ReadResourceRequestSchema, async (request) => {
|
|
52
|
+
const { uri } = request.params;
|
|
53
|
+
const content = await (0, resources_js_1.readResource)(client, uri);
|
|
54
|
+
return {
|
|
55
|
+
contents: [content],
|
|
56
|
+
};
|
|
57
|
+
});
|
|
58
|
+
const transport = new stdio_js_1.StdioServerTransport();
|
|
59
|
+
await server.connect(transport);
|
|
60
|
+
console.error("MCP Server running on stdio");
|
|
61
|
+
}
|
|
62
|
+
async function main() {
|
|
63
|
+
if ((0, config_js_1.shouldRunTest)()) {
|
|
64
|
+
await runTest();
|
|
65
|
+
return;
|
|
66
|
+
}
|
|
67
|
+
await runServer();
|
|
68
|
+
}
|
|
69
|
+
main().catch((err) => {
|
|
70
|
+
console.error("Fatal error:", err);
|
|
71
|
+
process.exit(1);
|
|
72
|
+
});
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import type { AxiosInstance } from "axios";
|
|
2
|
+
export declare const RESOURCES: {
|
|
3
|
+
uri: string;
|
|
4
|
+
name: string;
|
|
5
|
+
mimeType: string;
|
|
6
|
+
description: string;
|
|
7
|
+
}[];
|
|
8
|
+
export declare function readResource(client: AxiosInstance, uri: string): Promise<{
|
|
9
|
+
uri: string;
|
|
10
|
+
mimeType: string;
|
|
11
|
+
text: string;
|
|
12
|
+
}>;
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.RESOURCES = void 0;
|
|
4
|
+
exports.readResource = readResource;
|
|
5
|
+
exports.RESOURCES = [
|
|
6
|
+
{
|
|
7
|
+
uri: "modernity://health",
|
|
8
|
+
name: "API Health Status",
|
|
9
|
+
mimeType: "application/json",
|
|
10
|
+
description: "Current health and status of the Modernity API",
|
|
11
|
+
},
|
|
12
|
+
{
|
|
13
|
+
uri: "modernity://sources",
|
|
14
|
+
name: "Available Sources",
|
|
15
|
+
mimeType: "application/json",
|
|
16
|
+
description: "List of all data sources and categories",
|
|
17
|
+
},
|
|
18
|
+
{
|
|
19
|
+
uri: "modernity://pricing",
|
|
20
|
+
name: "Pricing Tiers",
|
|
21
|
+
mimeType: "application/json",
|
|
22
|
+
description: "Pricing tiers and feature comparison",
|
|
23
|
+
},
|
|
24
|
+
];
|
|
25
|
+
async function readResource(client, uri) {
|
|
26
|
+
let path;
|
|
27
|
+
switch (uri) {
|
|
28
|
+
case "modernity://health":
|
|
29
|
+
path = "/health";
|
|
30
|
+
break;
|
|
31
|
+
case "modernity://sources":
|
|
32
|
+
path = "/v1/sources";
|
|
33
|
+
break;
|
|
34
|
+
case "modernity://pricing":
|
|
35
|
+
path = "/v1/pricing";
|
|
36
|
+
break;
|
|
37
|
+
default:
|
|
38
|
+
throw new Error(`Resource not found: ${uri}`);
|
|
39
|
+
}
|
|
40
|
+
const res = await client.get(path);
|
|
41
|
+
return {
|
|
42
|
+
uri,
|
|
43
|
+
mimeType: "application/json",
|
|
44
|
+
text: JSON.stringify(res.data, null, 2),
|
|
45
|
+
};
|
|
46
|
+
}
|
package/dist/tools.d.ts
ADDED
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import type { AxiosInstance } from "axios";
|
|
2
|
+
export interface ToolDef {
|
|
3
|
+
name: string;
|
|
4
|
+
description: string;
|
|
5
|
+
inputSchema: {
|
|
6
|
+
type: "object";
|
|
7
|
+
properties: Record<string, unknown>;
|
|
8
|
+
};
|
|
9
|
+
}
|
|
10
|
+
export declare function getToolDefinitions(): ToolDef[];
|
|
11
|
+
export declare function handleToolCall(client: AxiosInstance, name: string, args: Record<string, unknown>): Promise<{
|
|
12
|
+
text: string;
|
|
13
|
+
isError?: boolean;
|
|
14
|
+
}>;
|
package/dist/tools.js
ADDED
|
@@ -0,0 +1,208 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.getToolDefinitions = getToolDefinitions;
|
|
4
|
+
exports.handleToolCall = handleToolCall;
|
|
5
|
+
function getToolDefinitions() {
|
|
6
|
+
return [
|
|
7
|
+
{
|
|
8
|
+
name: "get_recent_data",
|
|
9
|
+
description: "Fetch recent messages from the live stream buffer. Optionally filter by source or category.",
|
|
10
|
+
inputSchema: {
|
|
11
|
+
type: "object",
|
|
12
|
+
properties: {
|
|
13
|
+
limit: {
|
|
14
|
+
type: "number",
|
|
15
|
+
description: "Number of messages to return (default 100, max 1000)",
|
|
16
|
+
},
|
|
17
|
+
source: {
|
|
18
|
+
type: "string",
|
|
19
|
+
description: "Optional source filter (e.g. bluesky, coingecko, usgs)",
|
|
20
|
+
},
|
|
21
|
+
category: {
|
|
22
|
+
type: "string",
|
|
23
|
+
description: "Optional category filter (finance, crypto, social)",
|
|
24
|
+
},
|
|
25
|
+
},
|
|
26
|
+
},
|
|
27
|
+
},
|
|
28
|
+
{
|
|
29
|
+
name: "query_topic",
|
|
30
|
+
description: "Search for a topic across all data sources with configurable timeframe and limit.",
|
|
31
|
+
inputSchema: {
|
|
32
|
+
type: "object",
|
|
33
|
+
properties: {
|
|
34
|
+
topic: {
|
|
35
|
+
type: "string",
|
|
36
|
+
description: "Natural language topic or query to search for",
|
|
37
|
+
},
|
|
38
|
+
timeframe: {
|
|
39
|
+
type: "string",
|
|
40
|
+
description: "Data freshness: 60s, 5m, 10m, 20m, 1h, 24h (default 60s)",
|
|
41
|
+
},
|
|
42
|
+
limit: {
|
|
43
|
+
type: "number",
|
|
44
|
+
description: "Max results to return (default 10, max 100)",
|
|
45
|
+
},
|
|
46
|
+
format: {
|
|
47
|
+
type: "string",
|
|
48
|
+
description: "Output format: json or markdown (default json)",
|
|
49
|
+
},
|
|
50
|
+
},
|
|
51
|
+
},
|
|
52
|
+
},
|
|
53
|
+
{
|
|
54
|
+
name: "multi_schema_query",
|
|
55
|
+
description: "Query across multiple Vespa schemas (doc, ticker, news, geo_alert) with a single query string.",
|
|
56
|
+
inputSchema: {
|
|
57
|
+
type: "object",
|
|
58
|
+
properties: {
|
|
59
|
+
query: {
|
|
60
|
+
type: "string",
|
|
61
|
+
description: "Natural language query",
|
|
62
|
+
},
|
|
63
|
+
schemas: {
|
|
64
|
+
type: "array",
|
|
65
|
+
items: { type: "string" },
|
|
66
|
+
description: "Optional schemas to query: doc, ticker, news, geo_alert",
|
|
67
|
+
},
|
|
68
|
+
timeframe: {
|
|
69
|
+
type: "string",
|
|
70
|
+
description: "Data freshness: 60s, 5m, 10m, 20m, 1h, 24h (default 10m)",
|
|
71
|
+
},
|
|
72
|
+
limit: {
|
|
73
|
+
type: "number",
|
|
74
|
+
description: "Max results per schema (default 10, max 100)",
|
|
75
|
+
},
|
|
76
|
+
},
|
|
77
|
+
},
|
|
78
|
+
},
|
|
79
|
+
{
|
|
80
|
+
name: "analyze_topic",
|
|
81
|
+
description: "Use AI to analyze a topic and get query recommendations, relevant sources, and search terms.",
|
|
82
|
+
inputSchema: {
|
|
83
|
+
type: "object",
|
|
84
|
+
properties: {
|
|
85
|
+
topic: {
|
|
86
|
+
type: "string",
|
|
87
|
+
description: "Topic to analyze",
|
|
88
|
+
},
|
|
89
|
+
},
|
|
90
|
+
},
|
|
91
|
+
},
|
|
92
|
+
{
|
|
93
|
+
name: "get_sources",
|
|
94
|
+
description: "List all available data sources and categories.",
|
|
95
|
+
inputSchema: {
|
|
96
|
+
type: "object",
|
|
97
|
+
properties: {},
|
|
98
|
+
},
|
|
99
|
+
},
|
|
100
|
+
{
|
|
101
|
+
name: "get_stream_stats",
|
|
102
|
+
description: "Get live stream health and statistics (status, hub stats).",
|
|
103
|
+
inputSchema: {
|
|
104
|
+
type: "object",
|
|
105
|
+
properties: {},
|
|
106
|
+
},
|
|
107
|
+
},
|
|
108
|
+
{
|
|
109
|
+
name: "get_key_info",
|
|
110
|
+
description: "Check your API key tier, usage, rate limits, and remaining quotas.",
|
|
111
|
+
inputSchema: {
|
|
112
|
+
type: "object",
|
|
113
|
+
properties: {},
|
|
114
|
+
},
|
|
115
|
+
},
|
|
116
|
+
{
|
|
117
|
+
name: "check_health",
|
|
118
|
+
description: "Verify the Modernity API is online and healthy.",
|
|
119
|
+
inputSchema: {
|
|
120
|
+
type: "object",
|
|
121
|
+
properties: {},
|
|
122
|
+
},
|
|
123
|
+
},
|
|
124
|
+
{
|
|
125
|
+
name: "get_pricing",
|
|
126
|
+
description: "Get all pricing tiers and features.",
|
|
127
|
+
inputSchema: {
|
|
128
|
+
type: "object",
|
|
129
|
+
properties: {},
|
|
130
|
+
},
|
|
131
|
+
},
|
|
132
|
+
];
|
|
133
|
+
}
|
|
134
|
+
async function handleToolCall(client, name, args) {
|
|
135
|
+
try {
|
|
136
|
+
switch (name) {
|
|
137
|
+
case "get_recent_data": {
|
|
138
|
+
const limit = args.limit ?? 100;
|
|
139
|
+
const source = args.source;
|
|
140
|
+
const category = args.category;
|
|
141
|
+
const params = { limit };
|
|
142
|
+
if (source)
|
|
143
|
+
params.source = source;
|
|
144
|
+
if (category)
|
|
145
|
+
params.category = category;
|
|
146
|
+
const res = await client.get("/v1/recent", { params });
|
|
147
|
+
return { text: JSON.stringify(res.data, null, 2) };
|
|
148
|
+
}
|
|
149
|
+
case "query_topic": {
|
|
150
|
+
const topic = args.topic;
|
|
151
|
+
if (!topic)
|
|
152
|
+
throw new Error("topic is required");
|
|
153
|
+
const res = await client.post("/v1/query", {
|
|
154
|
+
topic,
|
|
155
|
+
timeframe: args.timeframe ?? "60s",
|
|
156
|
+
limit: args.limit ?? 10,
|
|
157
|
+
format: args.format ?? "json",
|
|
158
|
+
});
|
|
159
|
+
return { text: JSON.stringify(res.data, null, 2) };
|
|
160
|
+
}
|
|
161
|
+
case "multi_schema_query": {
|
|
162
|
+
const query = args.query;
|
|
163
|
+
if (!query)
|
|
164
|
+
throw new Error("query is required");
|
|
165
|
+
const res = await client.post("/v1/query/multi", {
|
|
166
|
+
query,
|
|
167
|
+
schemas: args.schemas,
|
|
168
|
+
timeframe: args.timeframe ?? "10m",
|
|
169
|
+
limit: args.limit ?? 10,
|
|
170
|
+
});
|
|
171
|
+
return { text: JSON.stringify(res.data, null, 2) };
|
|
172
|
+
}
|
|
173
|
+
case "analyze_topic": {
|
|
174
|
+
const topic = args.topic;
|
|
175
|
+
if (!topic)
|
|
176
|
+
throw new Error("topic is required");
|
|
177
|
+
const res = await client.post("/v1/analyze", { topic });
|
|
178
|
+
return { text: JSON.stringify(res.data, null, 2) };
|
|
179
|
+
}
|
|
180
|
+
case "get_sources": {
|
|
181
|
+
const res = await client.get("/v1/sources");
|
|
182
|
+
return { text: JSON.stringify(res.data, null, 2) };
|
|
183
|
+
}
|
|
184
|
+
case "get_stream_stats": {
|
|
185
|
+
const res = await client.get("/v1/live/stats");
|
|
186
|
+
return { text: JSON.stringify(res.data, null, 2) };
|
|
187
|
+
}
|
|
188
|
+
case "get_key_info": {
|
|
189
|
+
const res = await client.get("/v1/keys/info");
|
|
190
|
+
return { text: JSON.stringify(res.data, null, 2) };
|
|
191
|
+
}
|
|
192
|
+
case "check_health": {
|
|
193
|
+
const res = await client.get("/health");
|
|
194
|
+
return { text: JSON.stringify(res.data, null, 2) };
|
|
195
|
+
}
|
|
196
|
+
case "get_pricing": {
|
|
197
|
+
const res = await client.get("/v1/pricing");
|
|
198
|
+
return { text: JSON.stringify(res.data, null, 2) };
|
|
199
|
+
}
|
|
200
|
+
default:
|
|
201
|
+
throw new Error(`Tool not found: ${name}`);
|
|
202
|
+
}
|
|
203
|
+
}
|
|
204
|
+
catch (err) {
|
|
205
|
+
const msg = err instanceof Error ? err.message : String(err);
|
|
206
|
+
return { text: msg, isError: true };
|
|
207
|
+
}
|
|
208
|
+
}
|
package/package.json
ADDED
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "modernity-mcp",
|
|
3
|
+
"version": "1.0.0",
|
|
4
|
+
"description": "MCP server for Modernity — live data streaming for Cursor and Claude",
|
|
5
|
+
"main": "dist/index.js",
|
|
6
|
+
"bin": {
|
|
7
|
+
"modernity-mcp": "dist/index.js"
|
|
8
|
+
},
|
|
9
|
+
"scripts": {
|
|
10
|
+
"build": "tsc",
|
|
11
|
+
"prepublishOnly": "npm run build"
|
|
12
|
+
},
|
|
13
|
+
"keywords": [
|
|
14
|
+
"mcp",
|
|
15
|
+
"modernity",
|
|
16
|
+
"cursor",
|
|
17
|
+
"claude",
|
|
18
|
+
"live-data",
|
|
19
|
+
"streaming"
|
|
20
|
+
],
|
|
21
|
+
"license": "MIT",
|
|
22
|
+
"dependencies": {
|
|
23
|
+
"@modelcontextprotocol/sdk": "^1.0.0",
|
|
24
|
+
"axios": "^1.6.0"
|
|
25
|
+
},
|
|
26
|
+
"devDependencies": {
|
|
27
|
+
"@types/node": "^20.10.0",
|
|
28
|
+
"typescript": "^5.3.0"
|
|
29
|
+
},
|
|
30
|
+
"engines": {
|
|
31
|
+
"node": ">=18.0.0"
|
|
32
|
+
},
|
|
33
|
+
"files": [
|
|
34
|
+
"dist",
|
|
35
|
+
"README.md"
|
|
36
|
+
]
|
|
37
|
+
}
|