context-markets-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 +21 -0
- package/README.md +78 -0
- package/dist/index.d.ts +2 -0
- package/dist/index.js +32 -0
- package/dist/lib/client.d.ts +3 -0
- package/dist/lib/client.js +26 -0
- package/dist/lib/utils.d.ts +15 -0
- package/dist/lib/utils.js +26 -0
- package/dist/tools/account.d.ts +2 -0
- package/dist/tools/account.js +46 -0
- package/dist/tools/markets.d.ts +2 -0
- package/dist/tools/markets.js +138 -0
- package/dist/tools/orders.d.ts +2 -0
- package/dist/tools/orders.js +71 -0
- package/dist/tools/portfolio.d.ts +2 -0
- package/dist/tools/portfolio.js +34 -0
- package/dist/tools/questions.d.ts +2 -0
- package/dist/tools/questions.js +83 -0
- package/package.json +37 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2025 Context
|
|
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 all
|
|
13
|
+
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 THE
|
|
21
|
+
SOFTWARE.
|
package/README.md
ADDED
|
@@ -0,0 +1,78 @@
|
|
|
1
|
+
<p align="center">
|
|
2
|
+
<img src="https://mainnet.contextcdn.com/ced823d63df9dff0390d9ad0a4e1ad3905dd199a6c50758c18a5c92a203adbd7" alt="Context" width="100%" />
|
|
3
|
+
</p>
|
|
4
|
+
|
|
5
|
+
<h1 align="center">Context MCP Server</h1>
|
|
6
|
+
<p align="center">Browse, trade, and create prediction markets from any AI agent.</p>
|
|
7
|
+
|
|
8
|
+
<p align="center">
|
|
9
|
+
<a href="https://www.npmjs.com/package/context-markets-mcp"><img src="https://img.shields.io/npm/v/context-markets-mcp" alt="npm" /></a>
|
|
10
|
+
<a href="https://github.com/contextwtf/context-mcp/blob/main/LICENSE"><img src="https://img.shields.io/badge/license-MIT-blue" alt="License: MIT" /></a>
|
|
11
|
+
<a href="https://discord.gg/RVmzZsAyM4"><img src="https://img.shields.io/badge/Discord-Join-7289da" alt="Discord" /></a>
|
|
12
|
+
</p>
|
|
13
|
+
|
|
14
|
+
## Quick Start
|
|
15
|
+
|
|
16
|
+
### Claude Code
|
|
17
|
+
|
|
18
|
+
```bash
|
|
19
|
+
claude mcp add context-markets -- npx context-markets-mcp
|
|
20
|
+
```
|
|
21
|
+
|
|
22
|
+
### Claude Desktop
|
|
23
|
+
|
|
24
|
+
Add to your `claude_desktop_config.json`:
|
|
25
|
+
|
|
26
|
+
```json
|
|
27
|
+
{
|
|
28
|
+
"mcpServers": {
|
|
29
|
+
"context-markets": {
|
|
30
|
+
"command": "npx",
|
|
31
|
+
"args": ["context-markets-mcp"],
|
|
32
|
+
"env": {
|
|
33
|
+
"CONTEXT_API_KEY": "your-api-key",
|
|
34
|
+
"CONTEXT_PRIVATE_KEY": "your-wallet-private-key"
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
```
|
|
40
|
+
|
|
41
|
+
## Available Tools
|
|
42
|
+
|
|
43
|
+
### Read-only (no auth needed)
|
|
44
|
+
|
|
45
|
+
`context_list_markets` · `context_get_market` · `context_get_quotes` · `context_get_orderbook` · `context_simulate_trade` · `context_price_history` · `context_get_oracle` · `context_global_activity`
|
|
46
|
+
|
|
47
|
+
### Trading (requires API key + private key)
|
|
48
|
+
|
|
49
|
+
`context_place_order` · `context_cancel_order` · `context_my_orders` · `context_get_portfolio` · `context_get_balance` · `context_account_setup` · `context_mint_test_usdc` · `context_create_market`
|
|
50
|
+
|
|
51
|
+
## Environment Variables
|
|
52
|
+
|
|
53
|
+
| Variable | Required | Description |
|
|
54
|
+
|----------|----------|-------------|
|
|
55
|
+
| `CONTEXT_API_KEY` | For all tools | API key from context.markets |
|
|
56
|
+
| `CONTEXT_PRIVATE_KEY` | For trading only | Ethereum private key for signing |
|
|
57
|
+
|
|
58
|
+
Read-only tools work with zero config. Need an API key? Visit [context.markets](https://context.markets).
|
|
59
|
+
|
|
60
|
+
## Documentation
|
|
61
|
+
|
|
62
|
+
- **[Tool Catalog](https://docs.context.markets/agents/mcp/tools)** — full list of tools with parameters and examples
|
|
63
|
+
- **[MCP Guide](https://docs.context.markets/agents/mcp)** — setup, configuration, and usage patterns
|
|
64
|
+
|
|
65
|
+
## Ecosystem
|
|
66
|
+
|
|
67
|
+
| Package | Description |
|
|
68
|
+
|---------|-------------|
|
|
69
|
+
| **[context-markets](https://github.com/contextwtf/context-sdk)** | TypeScript SDK for trading |
|
|
70
|
+
| **[@contextwtf/react](https://github.com/contextwtf/context-react)** | React hooks for market data and trading |
|
|
71
|
+
| **[context-markets-mcp](https://github.com/contextwtf/context-mcp)** | MCP server for AI agents |
|
|
72
|
+
| **[@contextwtf/cli](https://github.com/contextwtf/context-cli)** | CLI for trading from the terminal |
|
|
73
|
+
| **[context-skills](https://github.com/contextwtf/context-skills)** | AI agent skill files |
|
|
74
|
+
| **[context-plugin](https://github.com/contextwtf/context-plugin)** | Claude Code plugin |
|
|
75
|
+
|
|
76
|
+
## License
|
|
77
|
+
|
|
78
|
+
MIT — see [LICENSE](./LICENSE) for details.
|
package/dist/index.d.ts
ADDED
package/dist/index.js
ADDED
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
|
|
3
|
+
import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
|
|
4
|
+
import dotenv from "dotenv";
|
|
5
|
+
import { fileURLToPath } from "url";
|
|
6
|
+
import { dirname, resolve } from "path";
|
|
7
|
+
import { registerMarketTools } from "./tools/markets.js";
|
|
8
|
+
import { registerOrderTools } from "./tools/orders.js";
|
|
9
|
+
import { registerPortfolioTools } from "./tools/portfolio.js";
|
|
10
|
+
import { registerAccountTools } from "./tools/account.js";
|
|
11
|
+
import { registerQuestionTools } from "./tools/questions.js";
|
|
12
|
+
const __filename = fileURLToPath(import.meta.url);
|
|
13
|
+
const __dirname = dirname(__filename);
|
|
14
|
+
dotenv.config({ path: resolve(__dirname, "..", ".env") });
|
|
15
|
+
const server = new McpServer({
|
|
16
|
+
name: "context-markets",
|
|
17
|
+
version: "0.1.0",
|
|
18
|
+
});
|
|
19
|
+
registerMarketTools(server);
|
|
20
|
+
registerOrderTools(server);
|
|
21
|
+
registerPortfolioTools(server);
|
|
22
|
+
registerAccountTools(server);
|
|
23
|
+
registerQuestionTools(server);
|
|
24
|
+
async function main() {
|
|
25
|
+
const transport = new StdioServerTransport();
|
|
26
|
+
await server.connect(transport);
|
|
27
|
+
console.error("Context Markets MCP server running");
|
|
28
|
+
}
|
|
29
|
+
main().catch((error) => {
|
|
30
|
+
console.error("Fatal:", error);
|
|
31
|
+
process.exit(1);
|
|
32
|
+
});
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
import { ContextClient } from "context-markets";
|
|
2
|
+
let readClientInstance = null;
|
|
3
|
+
let tradingClientInstance = null;
|
|
4
|
+
export function getReadClient() {
|
|
5
|
+
if (!readClientInstance) {
|
|
6
|
+
readClientInstance = new ContextClient({
|
|
7
|
+
apiKey: process.env.CONTEXT_API_KEY,
|
|
8
|
+
});
|
|
9
|
+
}
|
|
10
|
+
return readClientInstance;
|
|
11
|
+
}
|
|
12
|
+
export function getTradingClient() {
|
|
13
|
+
if (!tradingClientInstance) {
|
|
14
|
+
const apiKey = process.env.CONTEXT_API_KEY;
|
|
15
|
+
const privateKey = process.env.CONTEXT_PRIVATE_KEY;
|
|
16
|
+
if (!privateKey) {
|
|
17
|
+
throw new Error("CONTEXT_PRIVATE_KEY is required for trading operations. " +
|
|
18
|
+
"Set it in your MCP server env config.");
|
|
19
|
+
}
|
|
20
|
+
tradingClientInstance = new ContextClient({
|
|
21
|
+
apiKey,
|
|
22
|
+
signer: { privateKey: privateKey },
|
|
23
|
+
});
|
|
24
|
+
}
|
|
25
|
+
return tradingClientInstance;
|
|
26
|
+
}
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import type { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
|
|
2
|
+
export declare function toolResult(data: unknown): {
|
|
3
|
+
content: {
|
|
4
|
+
type: "text";
|
|
5
|
+
text: string;
|
|
6
|
+
}[];
|
|
7
|
+
};
|
|
8
|
+
export declare function toolError(error: unknown): {
|
|
9
|
+
content: {
|
|
10
|
+
type: "text";
|
|
11
|
+
text: string;
|
|
12
|
+
}[];
|
|
13
|
+
isError: true;
|
|
14
|
+
};
|
|
15
|
+
export type Server = InstanceType<typeof McpServer>;
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
export function toolResult(data) {
|
|
2
|
+
return {
|
|
3
|
+
content: [
|
|
4
|
+
{
|
|
5
|
+
type: "text",
|
|
6
|
+
text: typeof data === "string" ? data : JSON.stringify(data, null, 2),
|
|
7
|
+
},
|
|
8
|
+
],
|
|
9
|
+
};
|
|
10
|
+
}
|
|
11
|
+
export function toolError(error) {
|
|
12
|
+
let message;
|
|
13
|
+
if (error instanceof Error) {
|
|
14
|
+
message = error.message;
|
|
15
|
+
if ("status" in error && typeof error.status === "number") {
|
|
16
|
+
message = `[${error.status}] ${message}`;
|
|
17
|
+
}
|
|
18
|
+
}
|
|
19
|
+
else {
|
|
20
|
+
message = String(error);
|
|
21
|
+
}
|
|
22
|
+
return {
|
|
23
|
+
content: [{ type: "text", text: `Error: ${message}` }],
|
|
24
|
+
isError: true,
|
|
25
|
+
};
|
|
26
|
+
}
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
import { z } from "zod";
|
|
2
|
+
import { getTradingClient } from "../lib/client.js";
|
|
3
|
+
import { toolResult, toolError } from "../lib/utils.js";
|
|
4
|
+
export function registerAccountTools(server) {
|
|
5
|
+
// 1. Set up trading account
|
|
6
|
+
server.tool("context_account_setup", "Set up your trading account — approves USDC spending and operator permissions. Run this before your first trade. Requires CONTEXT_PRIVATE_KEY.", {}, async () => {
|
|
7
|
+
try {
|
|
8
|
+
const client = getTradingClient();
|
|
9
|
+
const status = await client.account.status();
|
|
10
|
+
if (!status.needsApprovals) {
|
|
11
|
+
return toolResult({
|
|
12
|
+
message: "Account already set up.",
|
|
13
|
+
status,
|
|
14
|
+
});
|
|
15
|
+
}
|
|
16
|
+
const result = await client.account.setup();
|
|
17
|
+
return toolResult({
|
|
18
|
+
message: "Account setup complete. You can now place trades.",
|
|
19
|
+
result,
|
|
20
|
+
});
|
|
21
|
+
}
|
|
22
|
+
catch (error) {
|
|
23
|
+
return toolError(error);
|
|
24
|
+
}
|
|
25
|
+
});
|
|
26
|
+
// 2. Mint test USDC
|
|
27
|
+
server.tool("context_mint_test_usdc", "Mint test USDC on Base Sepolia testnet for paper trading. Default 1000 USDC. Requires CONTEXT_PRIVATE_KEY.", {
|
|
28
|
+
amount: z
|
|
29
|
+
.number()
|
|
30
|
+
.describe("Amount of test USDC to mint (default 1000)")
|
|
31
|
+
.optional(),
|
|
32
|
+
}, async (params) => {
|
|
33
|
+
try {
|
|
34
|
+
const client = getTradingClient();
|
|
35
|
+
const mintAmount = params.amount ?? 1000;
|
|
36
|
+
await client.account.mintTestUsdc(mintAmount);
|
|
37
|
+
return toolResult({
|
|
38
|
+
message: `Minted ${mintAmount} test USDC successfully.`,
|
|
39
|
+
amount: mintAmount,
|
|
40
|
+
});
|
|
41
|
+
}
|
|
42
|
+
catch (error) {
|
|
43
|
+
return toolError(error);
|
|
44
|
+
}
|
|
45
|
+
});
|
|
46
|
+
}
|
|
@@ -0,0 +1,138 @@
|
|
|
1
|
+
import { z } from "zod";
|
|
2
|
+
import { getReadClient } from "../lib/client.js";
|
|
3
|
+
import { toolResult, toolError } from "../lib/utils.js";
|
|
4
|
+
export function registerMarketTools(server) {
|
|
5
|
+
// 1. List and search prediction markets
|
|
6
|
+
server.tool("context_list_markets", "List and search prediction markets on Context Markets. Returns market titles, prices, volume, and status.", {
|
|
7
|
+
query: z.string().describe("Search query to filter markets by title or description").optional(),
|
|
8
|
+
status: z
|
|
9
|
+
.enum(["active", "pending", "resolved", "closed"])
|
|
10
|
+
.describe("Filter by market status")
|
|
11
|
+
.optional(),
|
|
12
|
+
category: z.string().describe("Filter by market category").optional(),
|
|
13
|
+
sortBy: z
|
|
14
|
+
.enum(["new", "volume", "trending", "ending", "chance"])
|
|
15
|
+
.describe("Sort order for results")
|
|
16
|
+
.optional(),
|
|
17
|
+
limit: z.number().describe("Maximum number of markets to return").optional(),
|
|
18
|
+
}, async (params) => {
|
|
19
|
+
try {
|
|
20
|
+
const client = getReadClient();
|
|
21
|
+
const result = await client.markets.list({
|
|
22
|
+
query: params.query,
|
|
23
|
+
status: params.status,
|
|
24
|
+
sortBy: params.sortBy,
|
|
25
|
+
category: params.category,
|
|
26
|
+
limit: params.limit,
|
|
27
|
+
});
|
|
28
|
+
return toolResult(result);
|
|
29
|
+
}
|
|
30
|
+
catch (error) {
|
|
31
|
+
return toolError(error);
|
|
32
|
+
}
|
|
33
|
+
});
|
|
34
|
+
// 2. Get detailed market information
|
|
35
|
+
server.tool("context_get_market", "Get detailed information about a specific prediction market including description, resolution criteria, prices, and status.", {
|
|
36
|
+
marketId: z.string().describe("The unique identifier of the market"),
|
|
37
|
+
}, async (params) => {
|
|
38
|
+
try {
|
|
39
|
+
const client = getReadClient();
|
|
40
|
+
const result = await client.markets.get(params.marketId);
|
|
41
|
+
return toolResult(result);
|
|
42
|
+
}
|
|
43
|
+
catch (error) {
|
|
44
|
+
return toolError(error);
|
|
45
|
+
}
|
|
46
|
+
});
|
|
47
|
+
// 3. Get current quotes (bid/ask/last prices)
|
|
48
|
+
server.tool("context_get_quotes", "Get current bid/ask/last prices for a market's YES and NO outcomes. Prices are in cents (1-99 = 1%-99% probability).", {
|
|
49
|
+
marketId: z.string().describe("The unique identifier of the market"),
|
|
50
|
+
}, async (params) => {
|
|
51
|
+
try {
|
|
52
|
+
const client = getReadClient();
|
|
53
|
+
const result = await client.markets.quotes(params.marketId);
|
|
54
|
+
return toolResult(result);
|
|
55
|
+
}
|
|
56
|
+
catch (error) {
|
|
57
|
+
return toolError(error);
|
|
58
|
+
}
|
|
59
|
+
});
|
|
60
|
+
// 4. Get the orderbook
|
|
61
|
+
server.tool("context_get_orderbook", "Get the orderbook (bid/ask ladder) for a market. Shows available liquidity at each price level.", {
|
|
62
|
+
marketId: z.string().describe("The unique identifier of the market"),
|
|
63
|
+
depth: z.number().describe("Number of price levels to return on each side of the book").optional(),
|
|
64
|
+
}, async (params) => {
|
|
65
|
+
try {
|
|
66
|
+
const client = getReadClient();
|
|
67
|
+
const result = await client.markets.fullOrderbook(params.marketId, {
|
|
68
|
+
depth: params.depth,
|
|
69
|
+
});
|
|
70
|
+
return toolResult(result);
|
|
71
|
+
}
|
|
72
|
+
catch (error) {
|
|
73
|
+
return toolError(error);
|
|
74
|
+
}
|
|
75
|
+
});
|
|
76
|
+
// 5. Simulate a trade
|
|
77
|
+
server.tool("context_simulate_trade", "Simulate a trade to see estimated fill price, cost, and slippage before placing a real order. Does not execute.", {
|
|
78
|
+
marketId: z.string().describe("The unique identifier of the market"),
|
|
79
|
+
side: z.enum(["yes", "no"]).describe("Which outcome to buy: yes or no"),
|
|
80
|
+
amount: z.number().describe("Amount in USD to simulate trading"),
|
|
81
|
+
}, async (params) => {
|
|
82
|
+
try {
|
|
83
|
+
const client = getReadClient();
|
|
84
|
+
const result = await client.markets.simulate(params.marketId, {
|
|
85
|
+
side: params.side,
|
|
86
|
+
amount: params.amount,
|
|
87
|
+
amountType: "usd",
|
|
88
|
+
});
|
|
89
|
+
return toolResult(result);
|
|
90
|
+
}
|
|
91
|
+
catch (error) {
|
|
92
|
+
return toolError(error);
|
|
93
|
+
}
|
|
94
|
+
});
|
|
95
|
+
// 6. Get price history
|
|
96
|
+
server.tool("context_price_history", "Get historical price data for a market over a specified timeframe.", {
|
|
97
|
+
marketId: z.string().describe("The unique identifier of the market"),
|
|
98
|
+
timeframe: z
|
|
99
|
+
.enum(["1h", "6h", "1d", "1w", "1M", "all"])
|
|
100
|
+
.describe("Timeframe for the price history data")
|
|
101
|
+
.optional(),
|
|
102
|
+
}, async (params) => {
|
|
103
|
+
try {
|
|
104
|
+
const client = getReadClient();
|
|
105
|
+
const result = await client.markets.priceHistory(params.marketId, {
|
|
106
|
+
timeframe: params.timeframe,
|
|
107
|
+
});
|
|
108
|
+
return toolResult(result);
|
|
109
|
+
}
|
|
110
|
+
catch (error) {
|
|
111
|
+
return toolError(error);
|
|
112
|
+
}
|
|
113
|
+
});
|
|
114
|
+
// 7. Get oracle analysis
|
|
115
|
+
server.tool("context_get_oracle", "Get the AI oracle's resolution analysis for a market, including confidence level and sources monitored.", {
|
|
116
|
+
marketId: z.string().describe("The unique identifier of the market"),
|
|
117
|
+
}, async (params) => {
|
|
118
|
+
try {
|
|
119
|
+
const client = getReadClient();
|
|
120
|
+
const result = await client.markets.oracle(params.marketId);
|
|
121
|
+
return toolResult(result);
|
|
122
|
+
}
|
|
123
|
+
catch (error) {
|
|
124
|
+
return toolError(error);
|
|
125
|
+
}
|
|
126
|
+
});
|
|
127
|
+
// 8. Get global activity
|
|
128
|
+
server.tool("context_global_activity", "Get recent trading activity across all markets on Context Markets.", {}, async () => {
|
|
129
|
+
try {
|
|
130
|
+
const client = getReadClient();
|
|
131
|
+
const result = await client.markets.globalActivity();
|
|
132
|
+
return toolResult(result);
|
|
133
|
+
}
|
|
134
|
+
catch (error) {
|
|
135
|
+
return toolError(error);
|
|
136
|
+
}
|
|
137
|
+
});
|
|
138
|
+
}
|
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
import { z } from "zod";
|
|
2
|
+
import { getTradingClient } from "../lib/client.js";
|
|
3
|
+
import { toolResult, toolError } from "../lib/utils.js";
|
|
4
|
+
export function registerOrderTools(server) {
|
|
5
|
+
// 1. Place a buy order
|
|
6
|
+
server.tool("context_place_order", "Place a buy order on a prediction market. Requires CONTEXT_PRIVATE_KEY. Prices in cents (1-99), size in contracts (min 0.01).", {
|
|
7
|
+
marketId: z.string().describe("The unique identifier of the market"),
|
|
8
|
+
side: z.enum(["yes", "no"]).describe("Which outcome to buy: yes or no"),
|
|
9
|
+
size: z.number().describe("Number of contracts to buy (min 0.01)"),
|
|
10
|
+
price: z
|
|
11
|
+
.number()
|
|
12
|
+
.describe("Limit price in cents (1-99). Omit for a market order.")
|
|
13
|
+
.optional(),
|
|
14
|
+
}, async (params) => {
|
|
15
|
+
try {
|
|
16
|
+
const client = getTradingClient();
|
|
17
|
+
let result;
|
|
18
|
+
if (params.price !== undefined) {
|
|
19
|
+
result = await client.orders.create({
|
|
20
|
+
marketId: params.marketId,
|
|
21
|
+
outcome: params.side,
|
|
22
|
+
side: "buy",
|
|
23
|
+
priceCents: params.price,
|
|
24
|
+
size: params.size,
|
|
25
|
+
});
|
|
26
|
+
}
|
|
27
|
+
else {
|
|
28
|
+
result = await client.orders.createMarket({
|
|
29
|
+
marketId: params.marketId,
|
|
30
|
+
outcome: params.side,
|
|
31
|
+
side: "buy",
|
|
32
|
+
maxPriceCents: 99,
|
|
33
|
+
maxSize: params.size,
|
|
34
|
+
});
|
|
35
|
+
}
|
|
36
|
+
return toolResult(result);
|
|
37
|
+
}
|
|
38
|
+
catch (error) {
|
|
39
|
+
return toolError(error);
|
|
40
|
+
}
|
|
41
|
+
});
|
|
42
|
+
// 2. Cancel an open order
|
|
43
|
+
server.tool("context_cancel_order", "Cancel an open order by its nonce. Requires CONTEXT_PRIVATE_KEY.", {
|
|
44
|
+
nonce: z.string().describe("The nonce of the order to cancel"),
|
|
45
|
+
}, async (params) => {
|
|
46
|
+
try {
|
|
47
|
+
const client = getTradingClient();
|
|
48
|
+
const result = await client.orders.cancel(params.nonce);
|
|
49
|
+
return toolResult(result);
|
|
50
|
+
}
|
|
51
|
+
catch (error) {
|
|
52
|
+
return toolError(error);
|
|
53
|
+
}
|
|
54
|
+
});
|
|
55
|
+
// 3. List open orders
|
|
56
|
+
server.tool("context_my_orders", "List your open orders, optionally filtered to a specific market. Requires CONTEXT_PRIVATE_KEY.", {
|
|
57
|
+
marketId: z
|
|
58
|
+
.string()
|
|
59
|
+
.describe("Filter orders to a specific market")
|
|
60
|
+
.optional(),
|
|
61
|
+
}, async (params) => {
|
|
62
|
+
try {
|
|
63
|
+
const client = getTradingClient();
|
|
64
|
+
const result = await client.orders.allMine(params.marketId);
|
|
65
|
+
return toolResult(result);
|
|
66
|
+
}
|
|
67
|
+
catch (error) {
|
|
68
|
+
return toolError(error);
|
|
69
|
+
}
|
|
70
|
+
});
|
|
71
|
+
}
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
import { z } from "zod";
|
|
2
|
+
import { getTradingClient } from "../lib/client.js";
|
|
3
|
+
import { toolResult, toolError } from "../lib/utils.js";
|
|
4
|
+
export function registerPortfolioTools(server) {
|
|
5
|
+
// 1. Get portfolio positions
|
|
6
|
+
server.tool("context_get_portfolio", "Get your prediction market positions with P&L. Filter by kind: all, active, won, lost, or claimable. Requires CONTEXT_PRIVATE_KEY.", {
|
|
7
|
+
kind: z
|
|
8
|
+
.enum(["all", "active", "won", "lost", "claimable"])
|
|
9
|
+
.describe("Filter positions by kind")
|
|
10
|
+
.optional(),
|
|
11
|
+
}, async (params) => {
|
|
12
|
+
try {
|
|
13
|
+
const client = getTradingClient();
|
|
14
|
+
const result = await client.portfolio.get(undefined, {
|
|
15
|
+
kind: params.kind ?? "all",
|
|
16
|
+
});
|
|
17
|
+
return toolResult(result);
|
|
18
|
+
}
|
|
19
|
+
catch (error) {
|
|
20
|
+
return toolError(error);
|
|
21
|
+
}
|
|
22
|
+
});
|
|
23
|
+
// 2. Get balance
|
|
24
|
+
server.tool("context_get_balance", "Get your USDC balance (wallet + settlement) and outcome token holdings. Requires CONTEXT_PRIVATE_KEY.", {}, async () => {
|
|
25
|
+
try {
|
|
26
|
+
const client = getTradingClient();
|
|
27
|
+
const result = await client.portfolio.balance();
|
|
28
|
+
return toolResult(result);
|
|
29
|
+
}
|
|
30
|
+
catch (error) {
|
|
31
|
+
return toolError(error);
|
|
32
|
+
}
|
|
33
|
+
});
|
|
34
|
+
}
|
|
@@ -0,0 +1,83 @@
|
|
|
1
|
+
import { z } from "zod";
|
|
2
|
+
import { getTradingClient } from "../lib/client.js";
|
|
3
|
+
import { toolResult, toolError } from "../lib/utils.js";
|
|
4
|
+
export function registerQuestionTools(server) {
|
|
5
|
+
// 1. Create a new prediction market from a question
|
|
6
|
+
server.tool("context_create_market", "Create a new prediction market from a natural language question. The AI oracle processes the question and generates a market. This may take 30-90 seconds. Requires CONTEXT_PRIVATE_KEY.", {
|
|
7
|
+
question: z
|
|
8
|
+
.string()
|
|
9
|
+
.describe("A natural language question to create a prediction market for"),
|
|
10
|
+
}, async (params) => {
|
|
11
|
+
try {
|
|
12
|
+
const client = getTradingClient();
|
|
13
|
+
const submission = await client.questions.submitAndWait(params.question);
|
|
14
|
+
if (submission.status === "failed") {
|
|
15
|
+
return toolError("Oracle failed to process the question. Try rephrasing.");
|
|
16
|
+
}
|
|
17
|
+
if (!submission.questions?.length) {
|
|
18
|
+
return toolError("Oracle returned no market questions.");
|
|
19
|
+
}
|
|
20
|
+
const generated = submission.questions[0];
|
|
21
|
+
const market = await client.markets.create(generated.id);
|
|
22
|
+
return toolResult({
|
|
23
|
+
message: "Market created successfully!",
|
|
24
|
+
market,
|
|
25
|
+
generatedQuestion: generated,
|
|
26
|
+
});
|
|
27
|
+
}
|
|
28
|
+
catch (error) {
|
|
29
|
+
return toolError(error);
|
|
30
|
+
}
|
|
31
|
+
});
|
|
32
|
+
// 2. Submit a fully-formed market draft directly
|
|
33
|
+
server.tool("context_agent_submit_market", "Submit a fully-formed market draft with custom resolution criteria, wait for oracle approval, and create the market on-chain. This may take 30-90 seconds. Use this when you want full control over question, criteria, sources, and end time. Requires CONTEXT_PRIVATE_KEY.", {
|
|
34
|
+
formattedQuestion: z.string().describe("Full question text for the market"),
|
|
35
|
+
shortQuestion: z.string().describe("Short display title for the market"),
|
|
36
|
+
marketType: z.enum(["SUBJECTIVE", "OBJECTIVE"]).describe("Whether resolution is subjective (opinion-based) or objective (verifiable fact)"),
|
|
37
|
+
evidenceMode: z.enum(["social_only", "web_enabled"]).describe("Evidence sources: social_only for social signals, web_enabled for web scraping"),
|
|
38
|
+
resolutionCriteria: z.string().describe("Clear criteria for how this market should resolve"),
|
|
39
|
+
endTime: z.string().describe("Market end time as 'YYYY-MM-DD HH:MM:SS'"),
|
|
40
|
+
timezone: z.string().describe("IANA timezone identifier").default("America/New_York"),
|
|
41
|
+
sources: z.array(z.string()).describe("URLs to monitor for evidence").optional(),
|
|
42
|
+
explanation: z.string().max(120).describe("Brief explanation of the market (max 120 chars)").optional(),
|
|
43
|
+
}, async (params) => {
|
|
44
|
+
try {
|
|
45
|
+
const client = getTradingClient();
|
|
46
|
+
const submission = await client.questions.agentSubmitAndWait({
|
|
47
|
+
market: {
|
|
48
|
+
formattedQuestion: params.formattedQuestion,
|
|
49
|
+
shortQuestion: params.shortQuestion,
|
|
50
|
+
marketType: params.marketType,
|
|
51
|
+
evidenceMode: params.evidenceMode,
|
|
52
|
+
resolutionCriteria: params.resolutionCriteria,
|
|
53
|
+
endTime: params.endTime,
|
|
54
|
+
timezone: params.timezone,
|
|
55
|
+
sources: params.sources,
|
|
56
|
+
explanation: params.explanation,
|
|
57
|
+
},
|
|
58
|
+
});
|
|
59
|
+
if (submission.status === "failed") {
|
|
60
|
+
return toolError("Oracle failed to process the market draft. Try adjusting your criteria.");
|
|
61
|
+
}
|
|
62
|
+
if (submission.refuseToResolve) {
|
|
63
|
+
const reasons = submission.rejectionReasons
|
|
64
|
+
?.map((r) => r.message)
|
|
65
|
+
.join("; ");
|
|
66
|
+
return toolError(`Market draft rejected: ${reasons || "Unknown reason"}`);
|
|
67
|
+
}
|
|
68
|
+
if (!submission.questions?.length) {
|
|
69
|
+
return toolError("Oracle returned no market questions.");
|
|
70
|
+
}
|
|
71
|
+
const generated = submission.questions[0];
|
|
72
|
+
const market = await client.markets.create(generated.id);
|
|
73
|
+
return toolResult({
|
|
74
|
+
message: "Market created successfully!",
|
|
75
|
+
market,
|
|
76
|
+
generatedQuestion: generated,
|
|
77
|
+
});
|
|
78
|
+
}
|
|
79
|
+
catch (error) {
|
|
80
|
+
return toolError(error);
|
|
81
|
+
}
|
|
82
|
+
});
|
|
83
|
+
}
|
package/package.json
ADDED
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "context-markets-mcp",
|
|
3
|
+
"version": "0.1.0",
|
|
4
|
+
"description": "MCP server for Context Markets — browse, trade, and create prediction markets from any AI agent",
|
|
5
|
+
"type": "module",
|
|
6
|
+
"main": "dist/index.js",
|
|
7
|
+
"bin": {
|
|
8
|
+
"context-mcp": "dist/index.js"
|
|
9
|
+
},
|
|
10
|
+
"scripts": {
|
|
11
|
+
"build": "tsc",
|
|
12
|
+
"start": "node dist/index.js",
|
|
13
|
+
"dev": "tsc && node dist/index.js"
|
|
14
|
+
},
|
|
15
|
+
"dependencies": {
|
|
16
|
+
"context-markets": "^0.4.0",
|
|
17
|
+
"@modelcontextprotocol/sdk": "^1.0.0",
|
|
18
|
+
"dotenv": "^16.3.1",
|
|
19
|
+
"zod": "^3.22.0"
|
|
20
|
+
},
|
|
21
|
+
"devDependencies": {
|
|
22
|
+
"@types/node": "^22.0.0",
|
|
23
|
+
"typescript": "^5.7.0"
|
|
24
|
+
},
|
|
25
|
+
"files": ["dist"],
|
|
26
|
+
"keywords": ["mcp", "context-markets", "prediction-markets", "ai-agent"],
|
|
27
|
+
"license": "MIT",
|
|
28
|
+
"homepage": "https://docs.context.markets/agents/mcp",
|
|
29
|
+
"repository": {
|
|
30
|
+
"type": "git",
|
|
31
|
+
"url": "https://github.com/contextwtf/context-mcp.git"
|
|
32
|
+
},
|
|
33
|
+
"bugs": {
|
|
34
|
+
"url": "https://github.com/contextwtf/context-mcp/issues"
|
|
35
|
+
},
|
|
36
|
+
"author": "Context"
|
|
37
|
+
}
|