@midaslabs/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 +77 -0
- package/SKILL.md +41 -0
- package/dist/auth.d.ts +6 -0
- package/dist/auth.js +20 -0
- package/dist/config.d.ts +1 -0
- package/dist/config.js +10 -0
- package/dist/index.d.ts +2 -0
- package/dist/index.js +32 -0
- package/dist/server.d.ts +14 -0
- package/dist/server.js +42 -0
- package/package.json +33 -0
package/README.md
ADDED
|
@@ -0,0 +1,77 @@
|
|
|
1
|
+
# Midas MCP Server (`@midas/mcp`)
|
|
2
|
+
|
|
3
|
+
Trade crypto, equities, and prediction markets — and read your portfolio — directly from **Claude, Cursor, or any MCP-compatible client**, using the Midas AI trading tools.
|
|
4
|
+
|
|
5
|
+
`@midas/mcp` is a small local server you run via `npx`. It bridges your MCP client to the hosted Midas MCP endpoint, authenticated by a Midas API key. **No local wallet, no secrets beyond the key.** Every tool runs against the Midas API as your account.
|
|
6
|
+
|
|
7
|
+
## Quick start
|
|
8
|
+
|
|
9
|
+
1. **Get an API key** — in the Midas web app: **Settings → API keys (Developer) → Create key**. Copy the `midas_live_…` value (shown once).
|
|
10
|
+
|
|
11
|
+
2. **Add it to your MCP client config:**
|
|
12
|
+
|
|
13
|
+
**Claude Desktop** (`~/Library/Application Support/Claude/claude_desktop_config.json` on macOS):
|
|
14
|
+
```json
|
|
15
|
+
{
|
|
16
|
+
"mcpServers": {
|
|
17
|
+
"midas": {
|
|
18
|
+
"command": "npx",
|
|
19
|
+
"args": ["-y", "@midas/mcp"],
|
|
20
|
+
"env": { "MIDAS_API_KEY": "midas_live_your_key_here" }
|
|
21
|
+
}
|
|
22
|
+
}
|
|
23
|
+
}
|
|
24
|
+
```
|
|
25
|
+
|
|
26
|
+
**Cursor** (`.cursor/mcp.json` in your project, or the global Cursor MCP settings):
|
|
27
|
+
```json
|
|
28
|
+
{
|
|
29
|
+
"mcpServers": {
|
|
30
|
+
"midas": {
|
|
31
|
+
"command": "npx",
|
|
32
|
+
"args": ["-y", "@midas/mcp"],
|
|
33
|
+
"env": { "MIDAS_API_KEY": "midas_live_your_key_here" }
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
```
|
|
38
|
+
|
|
39
|
+
3. **Restart the client.** The Midas tools appear automatically.
|
|
40
|
+
|
|
41
|
+
## What you can do
|
|
42
|
+
|
|
43
|
+
- "Show my portfolio" / "What's my P&L?"
|
|
44
|
+
- "What's the price of ETH?" / "Search for BONK"
|
|
45
|
+
- "Preview a swap of $100 USDC into SOL" → confirm to execute
|
|
46
|
+
- "Bet $50 on Brazil to win on Polymarket"
|
|
47
|
+
- "Open a 2x long on BTC perps"
|
|
48
|
+
|
|
49
|
+
The full tool set (prices, market data, portfolio/positions, swaps, perps, Polymarket, World Cup markets) is whatever the Midas server exposes — this package proxies all of them, so it stays in sync with the API automatically.
|
|
50
|
+
|
|
51
|
+
> **Trades require confirmation.** Fund-moving actions (swaps, perps) return a preview; the agent confirms via a dedicated step before anything executes. This is enforced server-side.
|
|
52
|
+
|
|
53
|
+
## Configuration
|
|
54
|
+
|
|
55
|
+
| Env var | Required | Default | Purpose |
|
|
56
|
+
|---|---|---|---|
|
|
57
|
+
| `MIDAS_API_KEY` | **yes** | — | Your `midas_live_…` key. Missing → the server exits with a clear error. |
|
|
58
|
+
| `MIDAS_API_URL` | no | the hosted API | Override the API base (e.g. `http://localhost:3000` for local dev). The MCP endpoint is `${MIDAS_API_URL}/mcp`. |
|
|
59
|
+
|
|
60
|
+
## How it works
|
|
61
|
+
|
|
62
|
+
```
|
|
63
|
+
Claude / Cursor ──stdio──► @midas/mcp (this package) ──HTTPS + Bearer key──► Midas /mcp
|
|
64
|
+
```
|
|
65
|
+
|
|
66
|
+
It's a thin **bridge**: it doesn't reimplement any trading logic. It connects to the hosted Midas MCP server as a client and proxies `tools/list` + `tools/call` through. So all tools, all auth, and all trade safety live on the server — this package just makes them reachable from a local stdio MCP client.
|
|
67
|
+
|
|
68
|
+
## Troubleshooting
|
|
69
|
+
|
|
70
|
+
- **"MIDAS_API_KEY … not set"** — add the `env` block above with a real key.
|
|
71
|
+
- **Tools don't appear** — restart the MCP client after editing the config; check the key isn't revoked.
|
|
72
|
+
- **Local dev** — set `MIDAS_API_URL=http://localhost:3000` and make sure the API (with the `/mcp` endpoint) is running.
|
|
73
|
+
|
|
74
|
+
## Requirements
|
|
75
|
+
|
|
76
|
+
- Node.js ≥ 18.
|
|
77
|
+
- A Midas account + API key.
|
package/SKILL.md
ADDED
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: midas
|
|
3
|
+
description: Execute crypto trades, manage your portfolio, and access AI market analysis via Midas. Supports spot, perpetuals, and prediction markets.
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# Midas Trading Skill
|
|
7
|
+
|
|
8
|
+
Use Midas to trade assets, manage your portfolio, and research markets — crypto, equity perps, and prediction markets (Polymarket) — directly from your MCP client.
|
|
9
|
+
|
|
10
|
+
## Available tools
|
|
11
|
+
|
|
12
|
+
The skill proxies the full Midas MCP tool set, including:
|
|
13
|
+
|
|
14
|
+
- **Trading** — `preview_swap` (+ `confirm_action` to execute), `open_perps` / `close_perps`, `place_prediction_bet`. Swaps and perps go through a preview→confirm step before any funds move.
|
|
15
|
+
- **Markets & prices** — `quote_price`, `search_tokens` / `search_all_markets`, `get_market_orderbook`, `get_market_activity`.
|
|
16
|
+
- **Portfolio & positions** — Hyperliquid account, combo/prediction positions, order history.
|
|
17
|
+
- **Research** — `get_market_analysis`, World Cup market tools, `web_search`.
|
|
18
|
+
|
|
19
|
+
The exact list reflects whatever the Midas server exposes (the skill proxies it), so it stays current automatically.
|
|
20
|
+
|
|
21
|
+
## Setup
|
|
22
|
+
|
|
23
|
+
1. Generate a key in the Midas web app → **Settings → API keys (Developer)**.
|
|
24
|
+
2. Set `MIDAS_API_KEY` in your MCP client config (see the package README for Claude Desktop / Cursor JSON).
|
|
25
|
+
|
|
26
|
+
```json
|
|
27
|
+
{
|
|
28
|
+
"mcpServers": {
|
|
29
|
+
"midas": {
|
|
30
|
+
"command": "npx",
|
|
31
|
+
"args": ["-y", "@midas/mcp"],
|
|
32
|
+
"env": { "MIDAS_API_KEY": "midas_live_..." }
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
```
|
|
37
|
+
|
|
38
|
+
## Notes
|
|
39
|
+
|
|
40
|
+
- A key authenticates as **one Midas account** — the skill acts as that user.
|
|
41
|
+
- Fund-moving trades require explicit confirmation; the agent previews first.
|
package/dist/auth.d.ts
ADDED
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Reads the Midas API key from the environment. The MCP client (Claude Desktop,
|
|
3
|
+
* Cursor, …) injects it via the server's `env` block — see README. Fails loudly
|
|
4
|
+
* with a link rather than starting a server that 401s on every call.
|
|
5
|
+
*/
|
|
6
|
+
export declare function getApiKey(): string;
|
package/dist/auth.js
ADDED
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Reads the Midas API key from the environment. The MCP client (Claude Desktop,
|
|
3
|
+
* Cursor, …) injects it via the server's `env` block — see README. Fails loudly
|
|
4
|
+
* with a link rather than starting a server that 401s on every call.
|
|
5
|
+
*/
|
|
6
|
+
export function getApiKey() {
|
|
7
|
+
const key = process.env.MIDAS_API_KEY?.trim();
|
|
8
|
+
if (!key) {
|
|
9
|
+
throw new Error('MIDAS_API_KEY environment variable is not set.\n' +
|
|
10
|
+
'Generate a key in the Midas web app → Settings → API keys (Developer),\n' +
|
|
11
|
+
'then add it to your MCP client config, e.g.:\n' +
|
|
12
|
+
' "env": { "MIDAS_API_KEY": "midas_live_..." }');
|
|
13
|
+
}
|
|
14
|
+
// Keys are minted as `midas_live_<prefix>_<secret>`. A soft shape check catches
|
|
15
|
+
// an obviously-wrong value (e.g. a placeholder) before the first request.
|
|
16
|
+
if (!key.startsWith('midas_live_')) {
|
|
17
|
+
throw new Error(`MIDAS_API_KEY does not look like a Midas key (expected "midas_live_…", got "${key.slice(0, 12)}…").`);
|
|
18
|
+
}
|
|
19
|
+
return key;
|
|
20
|
+
}
|
package/dist/config.d.ts
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export declare function getMcpUrl(): URL;
|
package/dist/config.js
ADDED
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Where the hosted Midas MCP endpoint lives. Override with MIDAS_API_URL for
|
|
3
|
+
* local dev (e.g. http://localhost:3000) or a custom prod domain. The default
|
|
4
|
+
* is the deployed API host; the MCP endpoint is `${base}/mcp`.
|
|
5
|
+
*/
|
|
6
|
+
const DEFAULT_BASE_URL = 'https://stss-api-production.up.railway.app';
|
|
7
|
+
export function getMcpUrl() {
|
|
8
|
+
const base = (process.env.MIDAS_API_URL?.trim() || DEFAULT_BASE_URL).replace(/\/$/, '');
|
|
9
|
+
return new URL(`${base}/mcp`);
|
|
10
|
+
}
|
package/dist/index.d.ts
ADDED
package/dist/index.js
ADDED
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
import { StdioServerTransport } from '@modelcontextprotocol/sdk/server/stdio.js';
|
|
3
|
+
import { createBridgeServer } from './server.js';
|
|
4
|
+
// `npx @midas/mcp --version` / `-v` — print and exit (the bin contract).
|
|
5
|
+
// Reads the version from package.json without a JSON import assertion.
|
|
6
|
+
async function printVersionAndExit() {
|
|
7
|
+
const { readFile } = await import('node:fs/promises');
|
|
8
|
+
const { fileURLToPath } = await import('node:url');
|
|
9
|
+
const { dirname, join } = await import('node:path');
|
|
10
|
+
const here = dirname(fileURLToPath(import.meta.url));
|
|
11
|
+
const pkg = JSON.parse(await readFile(join(here, '..', 'package.json'), 'utf8'));
|
|
12
|
+
process.stdout.write(`${pkg.version}\n`);
|
|
13
|
+
process.exit(0);
|
|
14
|
+
}
|
|
15
|
+
async function main() {
|
|
16
|
+
const arg = process.argv[2];
|
|
17
|
+
if (arg === '--version' || arg === '-v') {
|
|
18
|
+
await printVersionAndExit();
|
|
19
|
+
return;
|
|
20
|
+
}
|
|
21
|
+
// getApiKey() (inside createBridgeServer) throws a friendly, link-bearing
|
|
22
|
+
// error when MIDAS_API_KEY is missing — surface it to stderr and exit non-zero
|
|
23
|
+
// so the MCP client shows a real failure instead of a silent hang.
|
|
24
|
+
const { server } = await createBridgeServer();
|
|
25
|
+
const transport = new StdioServerTransport();
|
|
26
|
+
await server.connect(transport);
|
|
27
|
+
// Stays alive on stdio; the client drives requests. Nothing else to do.
|
|
28
|
+
}
|
|
29
|
+
main().catch((err) => {
|
|
30
|
+
process.stderr.write(`[midas-mcp] ${err instanceof Error ? err.message : String(err)}\n`);
|
|
31
|
+
process.exit(1);
|
|
32
|
+
});
|
package/dist/server.d.ts
ADDED
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import { Server } from '@modelcontextprotocol/sdk/server/index.js';
|
|
2
|
+
import { Client } from '@modelcontextprotocol/sdk/client/index.js';
|
|
3
|
+
/**
|
|
4
|
+
* Builds the local stdio MCP server. It is a thin BRIDGE: it doesn't define
|
|
5
|
+
* tools itself — it connects (as an MCP client) to the hosted Midas MCP
|
|
6
|
+
* endpoint (`${MIDAS_API_URL}/mcp`) with the user's API key, and proxies
|
|
7
|
+
* tools/list + tools/call straight through. So every tool the hosted server
|
|
8
|
+
* exposes is available here with zero duplication, and trading still flows
|
|
9
|
+
* through the server's preview→confirm path unchanged.
|
|
10
|
+
*/
|
|
11
|
+
export declare function createBridgeServer(): Promise<{
|
|
12
|
+
server: Server;
|
|
13
|
+
upstream: Client;
|
|
14
|
+
}>;
|
package/dist/server.js
ADDED
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
import { Server } from '@modelcontextprotocol/sdk/server/index.js';
|
|
2
|
+
import { Client } from '@modelcontextprotocol/sdk/client/index.js';
|
|
3
|
+
import { StreamableHTTPClientTransport } from '@modelcontextprotocol/sdk/client/streamableHttp.js';
|
|
4
|
+
import { CallToolRequestSchema, ListToolsRequestSchema, } from '@modelcontextprotocol/sdk/types.js';
|
|
5
|
+
import { getApiKey } from './auth.js';
|
|
6
|
+
import { getMcpUrl } from './config.js';
|
|
7
|
+
/**
|
|
8
|
+
* Builds the local stdio MCP server. It is a thin BRIDGE: it doesn't define
|
|
9
|
+
* tools itself — it connects (as an MCP client) to the hosted Midas MCP
|
|
10
|
+
* endpoint (`${MIDAS_API_URL}/mcp`) with the user's API key, and proxies
|
|
11
|
+
* tools/list + tools/call straight through. So every tool the hosted server
|
|
12
|
+
* exposes is available here with zero duplication, and trading still flows
|
|
13
|
+
* through the server's preview→confirm path unchanged.
|
|
14
|
+
*/
|
|
15
|
+
export async function createBridgeServer() {
|
|
16
|
+
const apiKey = getApiKey();
|
|
17
|
+
// --- upstream: connect to the hosted /mcp as a client ---
|
|
18
|
+
const upstream = new Client({ name: 'midas-mcp-bridge', version: '1.0.0' }, { capabilities: {} });
|
|
19
|
+
const transport = new StreamableHTTPClientTransport(getMcpUrl(), {
|
|
20
|
+
requestInit: {
|
|
21
|
+
headers: { Authorization: `Bearer ${apiKey}` },
|
|
22
|
+
},
|
|
23
|
+
});
|
|
24
|
+
await upstream.connect(transport);
|
|
25
|
+
// --- downstream: the stdio server the MCP client (Claude/Cursor) talks to ---
|
|
26
|
+
const server = new Server({ name: 'midas', version: '1.0.0' }, { capabilities: { tools: {} } });
|
|
27
|
+
// Proxy: list the hosted server's tools verbatim.
|
|
28
|
+
server.setRequestHandler(ListToolsRequestSchema, async () => {
|
|
29
|
+
const { tools } = await upstream.listTools();
|
|
30
|
+
return { tools };
|
|
31
|
+
});
|
|
32
|
+
// Proxy: forward a tool call to the hosted server and relay the result.
|
|
33
|
+
server.setRequestHandler(CallToolRequestSchema, async (request) => {
|
|
34
|
+
const result = await upstream.callTool({
|
|
35
|
+
name: request.params.name,
|
|
36
|
+
arguments: request.params.arguments ?? {},
|
|
37
|
+
});
|
|
38
|
+
// The hosted server already returns a CallToolResult ({ content, isError }).
|
|
39
|
+
return result;
|
|
40
|
+
});
|
|
41
|
+
return { server, upstream };
|
|
42
|
+
}
|
package/package.json
ADDED
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@midaslabs/mcp",
|
|
3
|
+
"version": "1.0.0",
|
|
4
|
+
"description": "Midas AI trading MCP server — use Midas from Claude, Cursor, and any MCP client",
|
|
5
|
+
"license": "UNLICENSED",
|
|
6
|
+
"type": "module",
|
|
7
|
+
"bin": {
|
|
8
|
+
"midas-mcp": "./dist/index.js"
|
|
9
|
+
},
|
|
10
|
+
"main": "./dist/index.js",
|
|
11
|
+
"files": [
|
|
12
|
+
"dist",
|
|
13
|
+
"README.md",
|
|
14
|
+
"SKILL.md"
|
|
15
|
+
],
|
|
16
|
+
"scripts": {
|
|
17
|
+
"build": "tsc",
|
|
18
|
+
"start": "node dist/index.js",
|
|
19
|
+
"check-types": "tsc --noEmit",
|
|
20
|
+
"test": "npm run build && node --experimental-strip-types --test \"test/*.test.ts\"",
|
|
21
|
+
"prepublishOnly": "npm run build"
|
|
22
|
+
},
|
|
23
|
+
"dependencies": {
|
|
24
|
+
"@modelcontextprotocol/sdk": "^1.0.0"
|
|
25
|
+
},
|
|
26
|
+
"devDependencies": {
|
|
27
|
+
"@types/node": "^22.0.0",
|
|
28
|
+
"typescript": "^5.5.0"
|
|
29
|
+
},
|
|
30
|
+
"engines": {
|
|
31
|
+
"node": ">=18"
|
|
32
|
+
}
|
|
33
|
+
}
|