headless-oracle-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 +188 -0
- package/bin/cli.js +185 -0
- package/package.json +37 -0
package/README.md
ADDED
|
@@ -0,0 +1,188 @@
|
|
|
1
|
+
# headless-oracle-mcp
|
|
2
|
+
|
|
3
|
+
[](https://npmjs.com/package/headless-oracle-mcp)
|
|
4
|
+
[](https://opensource.org/licenses/MIT)
|
|
5
|
+
|
|
6
|
+
Local stdio MCP server for [Headless Oracle](https://headlessoracle.com) — Ed25519-signed market-state receipts for 28 global exchanges.
|
|
7
|
+
|
|
8
|
+
**Critical safety rule for agents:** treat `UNKNOWN` and `HALTED` as `CLOSED` — halt all execution.
|
|
9
|
+
|
|
10
|
+
---
|
|
11
|
+
|
|
12
|
+
## Quick start
|
|
13
|
+
|
|
14
|
+
```bash
|
|
15
|
+
npx headless-oracle-mcp
|
|
16
|
+
```
|
|
17
|
+
|
|
18
|
+
No install required. Works with Claude Desktop, Cursor, Cline, Windsurf, and Continue.dev.
|
|
19
|
+
|
|
20
|
+
---
|
|
21
|
+
|
|
22
|
+
## MCP client setup
|
|
23
|
+
|
|
24
|
+
### Claude Desktop
|
|
25
|
+
|
|
26
|
+
Edit `~/Library/Application Support/Claude/claude_desktop_config.json` (macOS) or `%APPDATA%\Claude\claude_desktop_config.json` (Windows):
|
|
27
|
+
|
|
28
|
+
```json
|
|
29
|
+
{
|
|
30
|
+
"mcpServers": {
|
|
31
|
+
"headless-oracle": {
|
|
32
|
+
"command": "npx",
|
|
33
|
+
"args": ["-y", "headless-oracle-mcp"]
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
```
|
|
38
|
+
|
|
39
|
+
### Cursor
|
|
40
|
+
|
|
41
|
+
Edit `~/.cursor/mcp.json`:
|
|
42
|
+
|
|
43
|
+
```json
|
|
44
|
+
{
|
|
45
|
+
"mcpServers": {
|
|
46
|
+
"headless-oracle": {
|
|
47
|
+
"command": "npx",
|
|
48
|
+
"args": ["-y", "headless-oracle-mcp"]
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
```
|
|
53
|
+
|
|
54
|
+
### Cline
|
|
55
|
+
|
|
56
|
+
Edit `cline_mcp_settings.json` (accessible via Cline settings → MCP Servers):
|
|
57
|
+
|
|
58
|
+
```json
|
|
59
|
+
{
|
|
60
|
+
"mcpServers": {
|
|
61
|
+
"headless-oracle": {
|
|
62
|
+
"command": "npx",
|
|
63
|
+
"args": ["-y", "headless-oracle-mcp"]
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
```
|
|
68
|
+
|
|
69
|
+
### Windsurf
|
|
70
|
+
|
|
71
|
+
Edit `~/.codeium/windsurf/mcp_config.json`:
|
|
72
|
+
|
|
73
|
+
```json
|
|
74
|
+
{
|
|
75
|
+
"mcpServers": {
|
|
76
|
+
"headless-oracle": {
|
|
77
|
+
"command": "npx",
|
|
78
|
+
"args": ["-y", "headless-oracle-mcp"]
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
```
|
|
83
|
+
|
|
84
|
+
### Continue.dev
|
|
85
|
+
|
|
86
|
+
Edit `~/.continue/config.json`:
|
|
87
|
+
|
|
88
|
+
```json
|
|
89
|
+
{
|
|
90
|
+
"experimental": {
|
|
91
|
+
"modelContextProtocolServers": [
|
|
92
|
+
{
|
|
93
|
+
"transport": {
|
|
94
|
+
"type": "stdio",
|
|
95
|
+
"command": "npx",
|
|
96
|
+
"args": ["-y", "headless-oracle-mcp"]
|
|
97
|
+
}
|
|
98
|
+
}
|
|
99
|
+
]
|
|
100
|
+
}
|
|
101
|
+
}
|
|
102
|
+
```
|
|
103
|
+
|
|
104
|
+
---
|
|
105
|
+
|
|
106
|
+
## With API key
|
|
107
|
+
|
|
108
|
+
For authenticated access (higher rate limits, `/v5/status` endpoint):
|
|
109
|
+
|
|
110
|
+
```json
|
|
111
|
+
{
|
|
112
|
+
"mcpServers": {
|
|
113
|
+
"headless-oracle": {
|
|
114
|
+
"command": "npx",
|
|
115
|
+
"args": ["-y", "headless-oracle-mcp"],
|
|
116
|
+
"env": {
|
|
117
|
+
"HEADLESS_ORACLE_API_KEY": "your-key-here"
|
|
118
|
+
}
|
|
119
|
+
}
|
|
120
|
+
}
|
|
121
|
+
}
|
|
122
|
+
```
|
|
123
|
+
|
|
124
|
+
Get a free sandbox key at [headlessoracle.com](https://headlessoracle.com) or via the `/v5/sandbox` endpoint.
|
|
125
|
+
|
|
126
|
+
---
|
|
127
|
+
|
|
128
|
+
## Tools
|
|
129
|
+
|
|
130
|
+
| Tool | Description |
|
|
131
|
+
|------|-------------|
|
|
132
|
+
| `get_market_status` | Returns an Ed25519-signed receipt: `OPEN`, `CLOSED`, `HALTED`, or `UNKNOWN`. Treat UNKNOWN/HALTED as CLOSED. |
|
|
133
|
+
| `get_market_schedule` | Returns next open/close times in UTC for a given exchange. |
|
|
134
|
+
| `list_exchanges` | Lists all 28 supported exchanges with MIC codes, names, and timezones. |
|
|
135
|
+
| `verify_receipt` | Verifies an Ed25519 receipt locally — checks signature, TTL, and fields. |
|
|
136
|
+
| `get_payment_options` | Returns the upgrade ladder (sandbox → x402 → credits → Builder). |
|
|
137
|
+
|
|
138
|
+
### Supported exchanges (28 total)
|
|
139
|
+
|
|
140
|
+
XNYS, XNAS, XBSP, XLON, XPAR, XSWX, XMIL, XHEL, XSTO, XIST, XSAU, XDFM, XJSE, XSHG, XSHE, XHKG, XJPX, XKRX, XBOM, XNSE, XSES, XASX, XNZE, XCBT, XNYM, XCBO, XCOI, XBIN
|
|
141
|
+
|
|
142
|
+
---
|
|
143
|
+
|
|
144
|
+
## Example receipt
|
|
145
|
+
|
|
146
|
+
```json
|
|
147
|
+
{
|
|
148
|
+
"mic": "XNYS",
|
|
149
|
+
"status": "OPEN",
|
|
150
|
+
"receipt_mode": "live",
|
|
151
|
+
"issued_at": "2026-04-04T14:30:00.000Z",
|
|
152
|
+
"expires_at": "2026-04-04T14:31:00.000Z",
|
|
153
|
+
"issuer": "headlessoracle.com",
|
|
154
|
+
"schema_version": "v5.0",
|
|
155
|
+
"source": "SCHEDULE",
|
|
156
|
+
"key_id": "ed25519-v1",
|
|
157
|
+
"receipt_id": "...",
|
|
158
|
+
"signature": "..."
|
|
159
|
+
}
|
|
160
|
+
```
|
|
161
|
+
|
|
162
|
+
All receipts are signed with Ed25519. Verify with [`@headlessoracle/verify`](https://npmjs.com/package/@headlessoracle/verify).
|
|
163
|
+
|
|
164
|
+
---
|
|
165
|
+
|
|
166
|
+
## How it works
|
|
167
|
+
|
|
168
|
+
This package is a local stdio MCP server that proxies tool calls to the [Headless Oracle remote endpoint](https://headlessoracle.com/mcp). Your MCP client (Claude Desktop, Cursor, etc.) communicates with this process over stdin/stdout using JSON-RPC 2.0. The process forwards `tools/list` and `tools/call` requests to the remote endpoint and returns the results.
|
|
169
|
+
|
|
170
|
+
- Zero npm dependencies — uses Node.js built-ins only (`readline`, `https`)
|
|
171
|
+
- Requires Node.js 18+
|
|
172
|
+
- Errors are logged to stderr only; stdout is reserved for the MCP transport
|
|
173
|
+
|
|
174
|
+
---
|
|
175
|
+
|
|
176
|
+
## Links
|
|
177
|
+
|
|
178
|
+
- **Website**: [headlessoracle.com](https://headlessoracle.com)
|
|
179
|
+
- **Docs**: [headlessoracle.com/docs](https://headlessoracle.com/docs)
|
|
180
|
+
- **npm**: [npmjs.com/package/@headlessoracle/verify](https://npmjs.com/package/@headlessoracle/verify) (JS verification SDK)
|
|
181
|
+
- **Remote MCP endpoint**: `https://headlessoracle.com/mcp` (MCP Streamable HTTP, protocol `2024-11-05`)
|
|
182
|
+
- **GitHub**: [github.com/LembaGang/headless-oracle-v5](https://github.com/LembaGang/headless-oracle-v5)
|
|
183
|
+
|
|
184
|
+
---
|
|
185
|
+
|
|
186
|
+
## License
|
|
187
|
+
|
|
188
|
+
MIT
|
package/bin/cli.js
ADDED
|
@@ -0,0 +1,185 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
'use strict';
|
|
3
|
+
|
|
4
|
+
// Headless Oracle — local stdio MCP server
|
|
5
|
+
// Proxies MCP tool calls to https://headlessoracle.com/mcp
|
|
6
|
+
// No external dependencies — uses Node.js built-ins only (readline, https)
|
|
7
|
+
|
|
8
|
+
const readline = require('readline');
|
|
9
|
+
const https = require('https');
|
|
10
|
+
|
|
11
|
+
const REMOTE_MCP_URL = 'https://headlessoracle.com/mcp';
|
|
12
|
+
const API_KEY = process.env.HEADLESS_ORACLE_API_KEY || '';
|
|
13
|
+
const SERVER_VERSION = '1.0.0';
|
|
14
|
+
|
|
15
|
+
// Write a JSON-RPC message to stdout (the MCP transport channel)
|
|
16
|
+
function send(obj) {
|
|
17
|
+
process.stdout.write(JSON.stringify(obj) + '\n');
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
// POST a JSON-RPC message to the remote MCP endpoint and return the parsed response
|
|
21
|
+
function proxyToRemote(body) {
|
|
22
|
+
return new Promise((resolve, reject) => {
|
|
23
|
+
const payload = JSON.stringify(body);
|
|
24
|
+
const headers = {
|
|
25
|
+
'Content-Type': 'application/json',
|
|
26
|
+
'Content-Length': Buffer.byteLength(payload),
|
|
27
|
+
'Accept': 'application/json',
|
|
28
|
+
'User-Agent': `headless-oracle-mcp/${SERVER_VERSION}`,
|
|
29
|
+
};
|
|
30
|
+
if (API_KEY) {
|
|
31
|
+
// X-Oracle-Key for REST auth; Authorization Bearer for MCP soft-auth
|
|
32
|
+
headers['X-Oracle-Key'] = API_KEY;
|
|
33
|
+
headers['Authorization'] = `Bearer ${API_KEY}`;
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
const url = new URL(REMOTE_MCP_URL);
|
|
37
|
+
const req = https.request(
|
|
38
|
+
{
|
|
39
|
+
hostname: url.hostname,
|
|
40
|
+
path: url.pathname + (url.search || ''),
|
|
41
|
+
method: 'POST',
|
|
42
|
+
headers,
|
|
43
|
+
},
|
|
44
|
+
(res) => {
|
|
45
|
+
let data = '';
|
|
46
|
+
res.on('data', (chunk) => { data += chunk; });
|
|
47
|
+
res.on('end', () => {
|
|
48
|
+
try {
|
|
49
|
+
resolve(JSON.parse(data));
|
|
50
|
+
} catch (e) {
|
|
51
|
+
reject(new Error(`Remote returned non-JSON (HTTP ${res.statusCode}): ${data.slice(0, 200)}`));
|
|
52
|
+
}
|
|
53
|
+
});
|
|
54
|
+
}
|
|
55
|
+
);
|
|
56
|
+
req.on('error', reject);
|
|
57
|
+
req.write(payload);
|
|
58
|
+
req.end();
|
|
59
|
+
});
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
// Handle one parsed JSON-RPC message
|
|
63
|
+
async function handleMessage(msg) {
|
|
64
|
+
const { method, id, params } = msg;
|
|
65
|
+
|
|
66
|
+
// Notifications (no id) — process silently, no response expected
|
|
67
|
+
if (id === undefined) {
|
|
68
|
+
// initialized notification is common; nothing to do
|
|
69
|
+
return;
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
// ── initialize ──────────────────────────────────────────────────────────────
|
|
73
|
+
if (method === 'initialize') {
|
|
74
|
+
send({
|
|
75
|
+
jsonrpc: '2.0',
|
|
76
|
+
id,
|
|
77
|
+
result: {
|
|
78
|
+
protocolVersion: '2024-11-05',
|
|
79
|
+
serverInfo: { name: 'headless-oracle', version: SERVER_VERSION },
|
|
80
|
+
capabilities: { tools: {} },
|
|
81
|
+
instructions:
|
|
82
|
+
'Headless Oracle provides Ed25519-signed market-state receipts for 28 global ' +
|
|
83
|
+
'exchanges (equities, derivatives, 24/7 crypto). ' +
|
|
84
|
+
'CRITICAL SAFETY RULE: treat UNKNOWN and HALTED as CLOSED — halt all execution immediately. ' +
|
|
85
|
+
'Call get_market_status before every trade. Receipts expire in 60 seconds. ' +
|
|
86
|
+
'SMA = Signed Market Attestation (not Simple Moving Average). ' +
|
|
87
|
+
'x402 micropayments accepted: $0.001 USDC per request on Base mainnet.',
|
|
88
|
+
},
|
|
89
|
+
});
|
|
90
|
+
return;
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
// ── ping ────────────────────────────────────────────────────────────────────
|
|
94
|
+
if (method === 'ping') {
|
|
95
|
+
send({ jsonrpc: '2.0', id, result: {} });
|
|
96
|
+
return;
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
// ── tools/list and tools/call — proxy to remote ─────────────────────────────
|
|
100
|
+
if (method === 'tools/list' || method === 'tools/call') {
|
|
101
|
+
try {
|
|
102
|
+
const remote = await proxyToRemote(msg);
|
|
103
|
+
// The remote response already has the correct id and jsonrpc fields.
|
|
104
|
+
// Forward it as-is.
|
|
105
|
+
send(remote);
|
|
106
|
+
} catch (err) {
|
|
107
|
+
process.stderr.write(`[headless-oracle-mcp] Remote error: ${err.message}\n`);
|
|
108
|
+
send({
|
|
109
|
+
jsonrpc: '2.0',
|
|
110
|
+
id,
|
|
111
|
+
error: {
|
|
112
|
+
code: -32603,
|
|
113
|
+
message: `Headless Oracle remote error: ${err.message}`,
|
|
114
|
+
},
|
|
115
|
+
});
|
|
116
|
+
}
|
|
117
|
+
return;
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
// ── resources/list and prompts/list — empty (not implemented) ───────────────
|
|
121
|
+
if (method === 'resources/list') {
|
|
122
|
+
send({ jsonrpc: '2.0', id, result: { resources: [] } });
|
|
123
|
+
return;
|
|
124
|
+
}
|
|
125
|
+
if (method === 'prompts/list') {
|
|
126
|
+
send({ jsonrpc: '2.0', id, result: { prompts: [] } });
|
|
127
|
+
return;
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
// ── unknown method ───────────────────────────────────────────────────────────
|
|
131
|
+
send({
|
|
132
|
+
jsonrpc: '2.0',
|
|
133
|
+
id,
|
|
134
|
+
error: { code: -32601, message: `Method not found: ${method}` },
|
|
135
|
+
});
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
// ── stdio transport ──────────────────────────────────────────────────────────
|
|
139
|
+
const rl = readline.createInterface({ input: process.stdin, terminal: false });
|
|
140
|
+
|
|
141
|
+
// Track in-flight async handlers so we don't exit before they complete
|
|
142
|
+
let pending = 0;
|
|
143
|
+
let stdinClosed = false;
|
|
144
|
+
|
|
145
|
+
function tryExit() {
|
|
146
|
+
if (stdinClosed && pending === 0) process.exit(0);
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
rl.on('line', async (line) => {
|
|
150
|
+
const trimmed = line.trim();
|
|
151
|
+
if (!trimmed) return;
|
|
152
|
+
|
|
153
|
+
let msg;
|
|
154
|
+
try {
|
|
155
|
+
msg = JSON.parse(trimmed);
|
|
156
|
+
} catch {
|
|
157
|
+
send({ jsonrpc: '2.0', id: null, error: { code: -32700, message: 'Parse error' } });
|
|
158
|
+
return;
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
pending++;
|
|
162
|
+
try {
|
|
163
|
+
await handleMessage(msg);
|
|
164
|
+
} catch (err) {
|
|
165
|
+
process.stderr.write(`[headless-oracle-mcp] Unhandled error: ${err.message}\n`);
|
|
166
|
+
if (msg.id !== undefined) {
|
|
167
|
+
send({
|
|
168
|
+
jsonrpc: '2.0',
|
|
169
|
+
id: msg.id,
|
|
170
|
+
error: { code: -32603, message: 'Internal error' },
|
|
171
|
+
});
|
|
172
|
+
}
|
|
173
|
+
} finally {
|
|
174
|
+
pending--;
|
|
175
|
+
tryExit();
|
|
176
|
+
}
|
|
177
|
+
});
|
|
178
|
+
|
|
179
|
+
rl.on('close', () => {
|
|
180
|
+
stdinClosed = true;
|
|
181
|
+
tryExit();
|
|
182
|
+
});
|
|
183
|
+
|
|
184
|
+
process.on('SIGINT', () => process.exit(0));
|
|
185
|
+
process.on('SIGTERM', () => process.exit(0));
|
package/package.json
ADDED
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "headless-oracle-mcp",
|
|
3
|
+
"version": "1.0.0",
|
|
4
|
+
"description": "Local MCP server for Headless Oracle — Ed25519-signed market-state receipts for 28 global exchanges",
|
|
5
|
+
"main": "bin/cli.js",
|
|
6
|
+
"bin": {
|
|
7
|
+
"headless-oracle-mcp": "./bin/cli.js"
|
|
8
|
+
},
|
|
9
|
+
"scripts": {
|
|
10
|
+
"start": "node bin/cli.js"
|
|
11
|
+
},
|
|
12
|
+
"keywords": [
|
|
13
|
+
"mcp",
|
|
14
|
+
"oracle",
|
|
15
|
+
"market-data",
|
|
16
|
+
"trading",
|
|
17
|
+
"ed25519",
|
|
18
|
+
"x402",
|
|
19
|
+
"market-status",
|
|
20
|
+
"exchange",
|
|
21
|
+
"ai-agent",
|
|
22
|
+
"signed-receipts"
|
|
23
|
+
],
|
|
24
|
+
"license": "MIT",
|
|
25
|
+
"repository": {
|
|
26
|
+
"type": "git",
|
|
27
|
+
"url": "https://github.com/LembaGang/headless-oracle-v5"
|
|
28
|
+
},
|
|
29
|
+
"homepage": "https://headlessoracle.com",
|
|
30
|
+
"bugs": {
|
|
31
|
+
"url": "https://github.com/LembaGang/headless-oracle-v5/issues"
|
|
32
|
+
},
|
|
33
|
+
"engines": {
|
|
34
|
+
"node": ">=18"
|
|
35
|
+
},
|
|
36
|
+
"dependencies": {}
|
|
37
|
+
}
|