@over.computer/mcp 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 ADDED
@@ -0,0 +1,24 @@
1
+ (The MIT License)
2
+
3
+ Copyright (c) 2009-2014 TJ Holowaychuk <tj@vision-media.ca>
4
+ Copyright (c) 2013-2014 Roman Shtylman <shtylman+expressjs@gmail.com>
5
+ Copyright (c) 2014-2015 Douglas Christopher Wilson <doug@somethingdoug.com>
6
+
7
+ Permission is hereby granted, free of charge, to any person obtaining
8
+ a copy of this software and associated documentation files (the
9
+ 'Software'), to deal in the Software without restriction, including
10
+ without limitation the rights to use, copy, modify, merge, publish,
11
+ distribute, sublicense, and/or sell copies of the Software, and to
12
+ permit persons to whom the Software is furnished to do so, subject to
13
+ the following conditions:
14
+
15
+ The above copyright notice and this permission notice shall be
16
+ included in all copies or substantial portions of the Software.
17
+
18
+ THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND,
19
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
20
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
21
+ IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
22
+ CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
23
+ TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
24
+ SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
package/README.md ADDED
@@ -0,0 +1,112 @@
1
+ # @over/mcp
2
+
3
+ [![npm version](https://img.shields.io/npm/v/@over/mcp)](https://www.npmjs.com/package/@over/mcp)
4
+ [![license](https://img.shields.io/npm/l/@over/mcp)](./LICENSE)
5
+
6
+ MCP server for over.computer.
7
+
8
+ Free trading diagnostic for autonomous agents. 10 scenarios across Polymarket and Hyperliquid. The first step into over.computer, a self-improving trading operating system.
9
+
10
+ ## Install
11
+
12
+ ```bash
13
+ npx @over/mcp
14
+ ```
15
+
16
+ ## Claude Desktop
17
+
18
+ Add to `~/Library/Application Support/Claude/claude_desktop_config.json`:
19
+
20
+ ```json
21
+ {
22
+ "mcpServers": {
23
+ "over": {
24
+ "command": "npx",
25
+ "args": ["-y", "@over/mcp"],
26
+ "env": {
27
+ "OVER_API_KEY": "your-api-key"
28
+ }
29
+ }
30
+ }
31
+ }
32
+ ```
33
+
34
+ ## Cursor
35
+
36
+ Add to `.cursor/mcp.json` in your project (or `~/.cursor/mcp.json` globally):
37
+
38
+ ```json
39
+ {
40
+ "mcpServers": {
41
+ "over": {
42
+ "command": "npx",
43
+ "args": ["-y", "@over/mcp"],
44
+ "env": {
45
+ "OVER_API_KEY": "your-api-key"
46
+ }
47
+ }
48
+ }
49
+ }
50
+ ```
51
+
52
+ ## ChatGPT (OpenAI MCP connector)
53
+
54
+ ```json
55
+ {
56
+ "name": "over",
57
+ "command": "npx",
58
+ "args": ["-y", "@over/mcp"],
59
+ "env": {
60
+ "OVER_API_KEY": "your-api-key"
61
+ }
62
+ }
63
+ ```
64
+
65
+ ## Resources
66
+
67
+ | URI | Description |
68
+ |-----|-------------|
69
+ | `over://markets` | List all live markets (Hyperliquid perps + Polymarket prediction markets) as JSON |
70
+ | `over://markets/{market_id}` | Get market state and order parameters for a specific market as JSON. Call for each market before placing an order. |
71
+
72
+ ## Tools
73
+
74
+ | Tool | Description |
75
+ |------|-------------|
76
+ | `place_order` | Execute a trade on Hyperliquid (`HL-*`) or Polymarket (`PM-*`) |
77
+
78
+
79
+ ### `place_order` parameters
80
+
81
+ | Parameter | Type | Required | Description |
82
+ |-----------|------|----------|-------------|
83
+ | `market_id` | string | yes | Market ID, e.g. `HL-1` or `PM-1` |
84
+ | `action` | enum | yes | `BUY` \| `SELL` \| `EXIT_FULL` \| `EXIT_PARTIAL` \| `SET_STOP_LOSS` \| `REDUCE_LEVERAGE` \| `HOLD` \| `NO_ACTION` \| `REJECT` \| `REQUEST_CONFIRMATION` \| `TRANSFER` \| `APPROVE` |
85
+ | `model` | string | yes | Model identifier for the agent |
86
+ | `details` | object | no | Order details (see below) |
87
+ | `risk_assessment` | string | no | Risk assessment |
88
+ | `urgency` | enum | no | `IMMEDIATE` \| `CAN_WAIT` \| `MONITORING` |
89
+
90
+ #### `details` fields
91
+
92
+ | Field | Type | Description |
93
+ |-------|------|-------------|
94
+ | `side` | string | `YES` \| `NO` \| `n/a` (Polymarket only) |
95
+ | `size_usd` | number | Position size in USD |
96
+ | `price` | number \| string | Limit price or `"market"` |
97
+ | `order_type` | string | `market` \| `limit` \| `twap` \| `n/a` |
98
+ | `leverage` | number | Leverage multiplier (perp only) |
99
+ | `reduce_only` | boolean | Whether order reduces position only (perp only) |
100
+ | `asset` | string | Asset symbol, e.g. `BTC-PERP` |
101
+ | `reasoning` | string | Agent's reasoning for the action |
102
+ | `to_address` | string | Destination address for transfers |
103
+ | `transfer_executed` | boolean | Whether a transfer was executed |
104
+ | `approval_executed` | boolean | Whether an approval was executed |
105
+
106
+ ## Configuration
107
+
108
+ Set `OVER_API_KEY` in your MCP client's `env` block as shown above. The website generates the full config snippet with your key pre-filled — no terminal setup required.
109
+
110
+ ## License
111
+
112
+ MIT
@@ -0,0 +1 @@
1
+ export declare function backendFetch(path: string, options: RequestInit | undefined, apiKey: string): Promise<Response>;
package/dist/client.js ADDED
@@ -0,0 +1,10 @@
1
+ const BASE_URL = "https://api.over.computer";
2
+ export async function backendFetch(path, options = {}, apiKey) {
3
+ const key = apiKey;
4
+ const headers = new Headers(options.headers);
5
+ headers.set("Authorization", `Bearer ${key}`);
6
+ if (!headers.has("Content-Type") && options.body) {
7
+ headers.set("Content-Type", "application/json");
8
+ }
9
+ return fetch(`${BASE_URL}${path}`, { ...options, headers });
10
+ }
@@ -0,0 +1 @@
1
+ export declare const API_KEY: string;
package/dist/config.js ADDED
@@ -0,0 +1 @@
1
+ export const API_KEY = process.env.OVER_API_KEY ?? "";
@@ -0,0 +1,2 @@
1
+ #!/usr/bin/env node
2
+ export {};
package/dist/index.js ADDED
@@ -0,0 +1,67 @@
1
+ #!/usr/bin/env node
2
+ import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
3
+ import { ResourceTemplate } from "@modelcontextprotocol/sdk/server/mcp.js";
4
+ import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
5
+ import { z } from "zod";
6
+ import { getMarkets } from "./resources/getMarkets.js";
7
+ import { getMarket } from "./resources/getMarket.js";
8
+ import { placeOrder } from "./tools/placeOrder.js";
9
+ const server = new McpServer({
10
+ name: "over-mcp",
11
+ version: "0.1.0",
12
+ });
13
+ // Step 1: List all live markets
14
+ server.resource("markets", "over://markets", { description: "List all live markets you are trading — Hyperliquid perpetual futures (HL-*) and Polymarket prediction markets (PM-*). Returns market IDs, names, platforms, and current portfolio balances." }, async (uri) => {
15
+ const result = await getMarkets();
16
+ return {
17
+ contents: [{ uri: uri.href, mimeType: "application/json", text: result }],
18
+ };
19
+ });
20
+ // Step 2: Get live market state and order parameters for a specific market
21
+ server.resource("market", new ResourceTemplate("over://markets/{market_id}", { list: undefined }), {
22
+ description: "Get the live market state and order parameters for a specific market. Returns the current portfolio position, live price action, and the exact response_format to use when executing your order. Call for each market before placing an order.",
23
+ }, async (uri, params) => {
24
+ const result = await getMarket(params.market_id);
25
+ return {
26
+ contents: [{ uri: uri.href, mimeType: "application/json", text: result }],
27
+ };
28
+ });
29
+ // Step 3: Execute an order
30
+ server.tool("place_order", "Execute a live trade on Hyperliquid (HL-*) or Polymarket (PM-*) via the Over relay. Use the response_format returned by get_market to determine the correct parameters for each market. Continue until all markets have an order submitted.", {
31
+ market_id: z
32
+ .string()
33
+ .regex(/^(HL|PM)-\d+$/)
34
+ .describe("Market ID, e.g. HL-1 or PM-1"),
35
+ action: z
36
+ .enum(["BUY", "SELL", "EXIT_FULL", "EXIT_PARTIAL", "SET_STOP_LOSS", "REDUCE_LEVERAGE", "HOLD", "NO_ACTION", "REJECT", "REQUEST_CONFIRMATION", "TRANSFER", "APPROVE"])
37
+ .describe("Trading action"),
38
+ model: z.string().describe("Model identifier for the agent"),
39
+ details: z.object({
40
+ side: z.enum(["YES", "NO", "n/a"]).optional().describe("Prediction market side (Polymarket only)"),
41
+ size_usd: z.number().optional().describe("Position size in USD"),
42
+ price: z.union([z.number(), z.string()]).optional().describe("Limit price or 'market'"),
43
+ order_type: z.string().optional().describe("market | limit | twap | n/a"),
44
+ leverage: z.number().optional().describe("Leverage multiplier (perp only)"),
45
+ reduce_only: z.boolean().optional().describe("Whether order reduces position only (perp only)"),
46
+ asset: z.string().optional().describe("Asset symbol e.g. BTC-PERP"),
47
+ reasoning: z.string().optional().describe("Agent's reasoning for the action"),
48
+ to_address: z.string().optional().describe("Destination address for transfers"),
49
+ transfer_executed: z.boolean().optional().describe("Whether a transfer was executed"),
50
+ approval_executed: z.boolean().optional().describe("Whether an approval was executed"),
51
+ }).optional().describe("Order details — shape depends on market type, see response_format from get_market"),
52
+ risk_assessment: z.string().optional().describe("Risk evaluation summary"),
53
+ urgency: z.enum(["IMMEDIATE", "CAN_WAIT", "MONITORING"]).optional().describe("Order urgency"),
54
+ }, async (params) => {
55
+ try {
56
+ const result = await placeOrder(params);
57
+ return { content: [{ type: "text", text: result }] };
58
+ }
59
+ catch (err) {
60
+ return {
61
+ content: [{ type: "text", text: err.message }],
62
+ isError: true,
63
+ };
64
+ }
65
+ });
66
+ const transport = new StdioServerTransport();
67
+ await server.connect(transport);
@@ -0,0 +1 @@
1
+ export declare function getMarket(marketId: string): Promise<string>;
@@ -0,0 +1,14 @@
1
+ import { backendFetch } from "../client.js";
2
+ import { API_KEY } from "../config.js";
3
+ export async function getMarket(marketId) {
4
+ const apiKey = API_KEY;
5
+ if (!apiKey)
6
+ throw new Error("API key not configured. Pass --api-key <key> or set OVER_API_KEY.");
7
+ const res = await backendFetch(`/v1/markets/${encodeURIComponent(marketId)}`, {}, apiKey);
8
+ if (!res.ok) {
9
+ const data = await res.json();
10
+ throw new Error(`Failed to fetch market ${marketId} (${res.status}): ${data.detail ?? JSON.stringify(data)}`);
11
+ }
12
+ const data = await res.json();
13
+ return JSON.stringify(data, null, 2);
14
+ }
@@ -0,0 +1 @@
1
+ export declare function getMarkets(): Promise<string>;
@@ -0,0 +1,14 @@
1
+ import { backendFetch } from "../client.js";
2
+ import { API_KEY } from "../config.js";
3
+ export async function getMarkets() {
4
+ const apiKey = API_KEY;
5
+ if (!apiKey)
6
+ throw new Error("API key not configured. Pass --api-key <key> or set OVER_API_KEY.");
7
+ const res = await backendFetch("/v1/markets", {}, apiKey);
8
+ if (!res.ok) {
9
+ const data = await res.json();
10
+ throw new Error(`Failed to fetch markets (${res.status}): ${data.detail ?? JSON.stringify(data)}`);
11
+ }
12
+ const data = await res.json();
13
+ return JSON.stringify(data.markets, null, 2);
14
+ }
@@ -0,0 +1,22 @@
1
+ import type { HLAction, PMAction, UrgencyLevel } from "../types.js";
2
+ export interface OrderParams {
3
+ market_id: string;
4
+ action: HLAction | PMAction;
5
+ model: string;
6
+ details?: {
7
+ side?: "YES" | "NO" | "n/a";
8
+ size_usd?: number;
9
+ price?: number | string;
10
+ order_type?: string;
11
+ leverage?: number;
12
+ reduce_only?: boolean;
13
+ asset?: string;
14
+ reasoning?: string;
15
+ to_address?: string;
16
+ transfer_executed?: boolean;
17
+ approval_executed?: boolean;
18
+ };
19
+ risk_assessment?: string;
20
+ urgency?: UrgencyLevel;
21
+ }
22
+ export declare function placeOrder(params: OrderParams): Promise<string>;
@@ -0,0 +1,19 @@
1
+ import { backendFetch } from "../client.js";
2
+ import { API_KEY } from "../config.js";
3
+ export async function placeOrder(params) {
4
+ const apiKey = API_KEY;
5
+ if (!apiKey)
6
+ throw new Error("OVER_API_KEY is not set.");
7
+ const body = params;
8
+ const res = await backendFetch("/v1/orders", {
9
+ method: "POST",
10
+ body: JSON.stringify(body),
11
+ }, apiKey);
12
+ const data = await res.json();
13
+ if (!res.ok) {
14
+ const err = data;
15
+ throw new Error(`Order failed (${res.status}): ${err.detail ?? JSON.stringify(data)}`);
16
+ }
17
+ const order = data;
18
+ return JSON.stringify(order, null, 2);
19
+ }
@@ -0,0 +1,28 @@
1
+ export type HLAction = "BUY" | "SELL" | "EXIT_FULL" | "EXIT_PARTIAL" | "SET_STOP_LOSS" | "REDUCE_LEVERAGE" | "HOLD" | "NO_ACTION" | "REJECT" | "REQUEST_CONFIRMATION" | "TRANSFER" | "APPROVE";
2
+ export type PMAction = "BUY" | "SELL" | "HOLD" | "NO_ACTION" | "REJECT" | "REQUEST_CONFIRMATION" | "TRANSFER" | "APPROVE";
3
+ export type UrgencyLevel = "IMMEDIATE" | "CAN_WAIT" | "MONITORING";
4
+ export interface Market {
5
+ market_id: string;
6
+ name: string;
7
+ platform: string;
8
+ category: string;
9
+ portfolio_balance: number;
10
+ }
11
+ export interface MarketDetail {
12
+ market_id: string;
13
+ platform: string;
14
+ market_state: string;
15
+ response_format: Record<string, unknown>;
16
+ }
17
+ export interface OrderResponse {
18
+ order_id: string;
19
+ market_id: string;
20
+ status: string;
21
+ action: string;
22
+ size_usd: number;
23
+ fill_price: number | null;
24
+ timestamp: string;
25
+ }
26
+ export interface ErrorResponse {
27
+ detail: string;
28
+ }
package/dist/types.js ADDED
@@ -0,0 +1 @@
1
+ export {};
package/package.json ADDED
@@ -0,0 +1,55 @@
1
+ {
2
+ "name": "@over.computer/mcp",
3
+ "version": "0.1.0",
4
+ "description": "MCP server for over.computer, a self-improving trading operating system.",
5
+ "keywords": [
6
+ "mcp",
7
+ "over",
8
+ "trading",
9
+ "hyperliquid",
10
+ "polymarket"
11
+ ],
12
+ "homepage": "https://github.com/overdriveapp/over-mcp#readme",
13
+ "bugs": {
14
+ "url": "https://github.com/overdriveapp/over-mcp/issues"
15
+ },
16
+ "repository": {
17
+ "type": "git",
18
+ "url": "git+https://github.com/overdriveapp/over-mcp.git"
19
+ },
20
+ "license": "MIT",
21
+ "author": "over.computer",
22
+ "type": "module",
23
+ "main": "./dist/index.js",
24
+ "types": "./dist/index.d.ts",
25
+ "bin": {
26
+ "over-mcp": "dist/index.js"
27
+ },
28
+ "directories": {
29
+ "test": "test"
30
+ },
31
+ "files": [
32
+ "dist",
33
+ "src",
34
+ "README.md",
35
+ "LICENSE"
36
+ ],
37
+ "scripts": {
38
+ "build": "tsc",
39
+ "test": "tsx test/run-tests.ts",
40
+ "test:live": "tsx test/run-tests-live.ts",
41
+ "prepublishOnly": "npm run build"
42
+ },
43
+ "dependencies": {
44
+ "@modelcontextprotocol/sdk": "^1.27.1",
45
+ "zod": "^3.22.0"
46
+ },
47
+ "devDependencies": {
48
+ "typescript": "^5.0.0",
49
+ "tsx": "^4.21.0",
50
+ "@types/node": "^20.0.0"
51
+ },
52
+ "engines": {
53
+ "node": ">=18.0.0"
54
+ }
55
+ }
package/src/client.ts ADDED
@@ -0,0 +1,15 @@
1
+ const BASE_URL = "https://api.over.computer";
2
+
3
+ export async function backendFetch(
4
+ path: string,
5
+ options: RequestInit = {},
6
+ apiKey: string
7
+ ): Promise<Response> {
8
+ const key = apiKey;
9
+ const headers = new Headers(options.headers);
10
+ headers.set("Authorization", `Bearer ${key}`);
11
+ if (!headers.has("Content-Type") && options.body) {
12
+ headers.set("Content-Type", "application/json");
13
+ }
14
+ return fetch(`${BASE_URL}${path}`, { ...options, headers });
15
+ }
package/src/config.ts ADDED
@@ -0,0 +1 @@
1
+ export const API_KEY = process.env.OVER_API_KEY ?? "";
package/src/index.ts ADDED
@@ -0,0 +1,82 @@
1
+ #!/usr/bin/env node
2
+ import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
3
+ import { ResourceTemplate } from "@modelcontextprotocol/sdk/server/mcp.js";
4
+ import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
5
+ import { z } from "zod";
6
+ import { getMarkets } from "./resources/getMarkets.js";
7
+ import { getMarket } from "./resources/getMarket.js";
8
+ import { placeOrder } from "./tools/placeOrder.js";
9
+
10
+ const server = new McpServer({
11
+ name: "over-mcp",
12
+ version: "0.1.0",
13
+ });
14
+
15
+ // Step 1: List all live markets
16
+ server.resource("markets", "over://markets", { description: "List all live markets you are trading — Hyperliquid perpetual futures (HL-*) and Polymarket prediction markets (PM-*). Returns market IDs, names, platforms, and current portfolio balances." }, async (uri) => {
17
+ const result = await getMarkets();
18
+ return {
19
+ contents: [{ uri: uri.href, mimeType: "application/json", text: result }],
20
+ };
21
+ });
22
+
23
+ // Step 2: Get live market state and order parameters for a specific market
24
+ server.resource(
25
+ "market",
26
+ new ResourceTemplate("over://markets/{market_id}", { list: undefined }),
27
+ {
28
+ description:
29
+ "Get the live market state and order parameters for a specific market. Returns the current portfolio position, live price action, and the exact response_format to use when executing your order. Call for each market before placing an order.",
30
+ },
31
+ async (uri, params) => {
32
+ const result = await getMarket(params.market_id as string);
33
+ return {
34
+ contents: [{ uri: uri.href, mimeType: "application/json", text: result }],
35
+ };
36
+ },
37
+ );
38
+
39
+ // Step 3: Execute an order
40
+ server.tool(
41
+ "place_order",
42
+ "Execute a live trade on Hyperliquid (HL-*) or Polymarket (PM-*) via the Over relay. Use the response_format returned by get_market to determine the correct parameters for each market. Continue until all markets have an order submitted.",
43
+ {
44
+ market_id: z
45
+ .string()
46
+ .regex(/^(HL|PM)-\d+$/)
47
+ .describe("Market ID, e.g. HL-1 or PM-1"),
48
+ action: z
49
+ .enum(["BUY", "SELL", "EXIT_FULL", "EXIT_PARTIAL", "SET_STOP_LOSS", "REDUCE_LEVERAGE", "HOLD", "NO_ACTION", "REJECT", "REQUEST_CONFIRMATION", "TRANSFER", "APPROVE"])
50
+ .describe("Trading action"),
51
+ model: z.string().describe("Model identifier for the agent"),
52
+ details: z.object({
53
+ side: z.enum(["YES", "NO", "n/a"]).optional().describe("Prediction market side (Polymarket only)"),
54
+ size_usd: z.number().optional().describe("Position size in USD"),
55
+ price: z.union([z.number(), z.string()]).optional().describe("Limit price or 'market'"),
56
+ order_type: z.string().optional().describe("market | limit | twap | n/a"),
57
+ leverage: z.number().optional().describe("Leverage multiplier (perp only)"),
58
+ reduce_only: z.boolean().optional().describe("Whether order reduces position only (perp only)"),
59
+ asset: z.string().optional().describe("Asset symbol e.g. BTC-PERP"),
60
+ reasoning: z.string().optional().describe("Agent's reasoning for the action"),
61
+ to_address: z.string().optional().describe("Destination address for transfers"),
62
+ transfer_executed: z.boolean().optional().describe("Whether a transfer was executed"),
63
+ approval_executed: z.boolean().optional().describe("Whether an approval was executed"),
64
+ }).optional().describe("Order details — shape depends on market type, see response_format from get_market"),
65
+ risk_assessment: z.string().optional().describe("Risk evaluation summary"),
66
+ urgency: z.enum(["IMMEDIATE", "CAN_WAIT", "MONITORING"]).optional().describe("Order urgency"),
67
+ },
68
+ async (params) => {
69
+ try {
70
+ const result = await placeOrder(params as Parameters<typeof placeOrder>[0]);
71
+ return { content: [{ type: "text", text: result }] };
72
+ } catch (err) {
73
+ return {
74
+ content: [{ type: "text", text: (err as Error).message }],
75
+ isError: true,
76
+ };
77
+ }
78
+ },
79
+ );
80
+
81
+ const transport = new StdioServerTransport();
82
+ await server.connect(transport);
@@ -0,0 +1,15 @@
1
+ import { backendFetch } from "../client.js";
2
+ import { API_KEY } from "../config.js";
3
+ import type { MarketDetail } from "../types.js";
4
+
5
+ export async function getMarket(marketId: string): Promise<string> {
6
+ const apiKey = API_KEY;
7
+ if (!apiKey) throw new Error("API key not configured. Pass --api-key <key> or set OVER_API_KEY.");
8
+ const res = await backendFetch(`/v1/markets/${encodeURIComponent(marketId)}`, {}, apiKey);
9
+ if (!res.ok) {
10
+ const data = await res.json() as { detail?: string };
11
+ throw new Error(`Failed to fetch market ${marketId} (${res.status}): ${data.detail ?? JSON.stringify(data)}`);
12
+ }
13
+ const data = await res.json() as MarketDetail;
14
+ return JSON.stringify(data, null, 2);
15
+ }
@@ -0,0 +1,15 @@
1
+ import { backendFetch } from "../client.js";
2
+ import { API_KEY } from "../config.js";
3
+ import type { Market } from "../types.js";
4
+
5
+ export async function getMarkets(): Promise<string> {
6
+ const apiKey = API_KEY;
7
+ if (!apiKey) throw new Error("API key not configured. Pass --api-key <key> or set OVER_API_KEY.");
8
+ const res = await backendFetch("/v1/markets", {}, apiKey);
9
+ if (!res.ok) {
10
+ const data = await res.json() as { detail?: string };
11
+ throw new Error(`Failed to fetch markets (${res.status}): ${data.detail ?? JSON.stringify(data)}`);
12
+ }
13
+ const data = await res.json() as { markets: Market[] };
14
+ return JSON.stringify(data.markets, null, 2);
15
+ }
@@ -0,0 +1,41 @@
1
+ import { backendFetch } from "../client.js";
2
+ import { API_KEY } from "../config.js";
3
+ import type { HLAction, PMAction, UrgencyLevel, OrderResponse, ErrorResponse } from "../types.js";
4
+
5
+ export interface OrderParams {
6
+ market_id: string;
7
+ action: HLAction | PMAction;
8
+ model: string;
9
+ details?: {
10
+ side?: "YES" | "NO" | "n/a";
11
+ size_usd?: number;
12
+ price?: number | string;
13
+ order_type?: string;
14
+ leverage?: number;
15
+ reduce_only?: boolean;
16
+ asset?: string;
17
+ reasoning?: string;
18
+ to_address?: string;
19
+ transfer_executed?: boolean;
20
+ approval_executed?: boolean;
21
+ };
22
+ risk_assessment?: string;
23
+ urgency?: UrgencyLevel;
24
+ }
25
+
26
+ export async function placeOrder(params: OrderParams): Promise<string> {
27
+ const apiKey = API_KEY;
28
+ if (!apiKey) throw new Error("OVER_API_KEY is not set.");
29
+ const body = params;
30
+ const res = await backendFetch("/v1/orders", {
31
+ method: "POST",
32
+ body: JSON.stringify(body),
33
+ }, apiKey);
34
+ const data = await res.json() as OrderResponse | ErrorResponse;
35
+ if (!res.ok) {
36
+ const err = data as ErrorResponse;
37
+ throw new Error(`Order failed (${res.status}): ${err.detail ?? JSON.stringify(data)}`);
38
+ }
39
+ const order = data as OrderResponse;
40
+ return JSON.stringify(order, null, 2);
41
+ }
package/src/types.ts ADDED
@@ -0,0 +1,46 @@
1
+ export type HLAction =
2
+ | "BUY"
3
+ | "SELL"
4
+ | "EXIT_FULL"
5
+ | "EXIT_PARTIAL"
6
+ | "SET_STOP_LOSS"
7
+ | "REDUCE_LEVERAGE"
8
+ | "HOLD"
9
+ | "NO_ACTION"
10
+ | "REJECT"
11
+ | "REQUEST_CONFIRMATION"
12
+ | "TRANSFER"
13
+ | "APPROVE";
14
+
15
+ export type PMAction = "BUY" | "SELL" | "HOLD" | "NO_ACTION" | "REJECT" | "REQUEST_CONFIRMATION" | "TRANSFER" | "APPROVE";
16
+
17
+ export type UrgencyLevel = "IMMEDIATE" | "CAN_WAIT" | "MONITORING";
18
+
19
+ export interface Market {
20
+ market_id: string;
21
+ name: string;
22
+ platform: string;
23
+ category: string;
24
+ portfolio_balance: number;
25
+ }
26
+
27
+ export interface MarketDetail {
28
+ market_id: string;
29
+ platform: string;
30
+ market_state: string;
31
+ response_format: Record<string, unknown>;
32
+ }
33
+
34
+ export interface OrderResponse {
35
+ order_id: string;
36
+ market_id: string;
37
+ status: string;
38
+ action: string;
39
+ size_usd: number;
40
+ fill_price: number | null;
41
+ timestamp: string;
42
+ }
43
+
44
+ export interface ErrorResponse {
45
+ detail: string;
46
+ }