@panoptic-eng/mcp 0.1.33 → 0.1.35
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 +11 -4
- package/dist/cli.js +3 -2
- package/dist/index.d.ts +9 -3
- package/dist/index.js +1 -1
- package/dist/{server-CabyB7Fb.js → server-DB4yvrb5.js} +36 -15
- package/package.json +2 -2
package/README.md
CHANGED
|
@@ -22,7 +22,7 @@ its MCP settings, etc.).
|
|
|
22
22
|
"command": "npx",
|
|
23
23
|
"args": ["-y", "@panoptic-eng/mcp"],
|
|
24
24
|
"env": {
|
|
25
|
-
"PANOPTIC_RPC_URL": "
|
|
25
|
+
"PANOPTIC_RPC_URL": "<RPC URL>",
|
|
26
26
|
"PANOPTIC_CHAIN_ID": "1",
|
|
27
27
|
// optional — enables enhanced analytics tools
|
|
28
28
|
"PANOPTIC_SUBGRAPH_URL": ""
|
|
@@ -35,9 +35,16 @@ its MCP settings, etc.).
|
|
|
35
35
|
Configuration may also be passed as CLI flags, which override the env vars:
|
|
36
36
|
|
|
37
37
|
```bash
|
|
38
|
-
npx @panoptic-eng/mcp --rpc-url
|
|
38
|
+
npx @panoptic-eng/mcp --rpc-url <RPC URL> --chain-id 1
|
|
39
39
|
```
|
|
40
40
|
|
|
41
|
+
`--rpc-url` is used as-is, and existing `PANOPTIC_RPC_URL` setups keep working.
|
|
42
|
+
Without the flag, the RPC resolves from `RPC_URL_<chainId>` (comma-separated
|
|
43
|
+
URLs or provider names, primary first, with optional
|
|
44
|
+
`RPC_HEADERS_<chainId>_<n>` headers), then `PANOPTIC_RPC_URL`, then a provider
|
|
45
|
+
API key (`ALCHEMY_API_KEY`, `UNIBLOCK_API_KEY`, `INFURA_API_KEY`; order set by
|
|
46
|
+
`RPC_PROVIDERS`). See `docs/rpc.md` in the Panoptic monorepo.
|
|
47
|
+
|
|
41
48
|
Supported chains: Ethereum mainnet (`1`), Sepolia (`11155111`).
|
|
42
49
|
|
|
43
50
|
## v0 tools (read-only)
|
|
@@ -57,7 +64,7 @@ session preferences rather than reading the chain.
|
|
|
57
64
|
| `liquidity_map` | Tick liquidity distribution around the current tick. |
|
|
58
65
|
| `chunk_spread` | Per-chunk spread multiplier (via `scanChunks`): ~1.0x chunks are cheapest to BUY (lowest IV), high-multiplier chunks are most profitable to SELL. Width defaults to a standard timescale (`STANDARD_TICK_WIDTHS`). |
|
|
59
66
|
| `suggest_delta_hedge` | Net delta (positions + collateral) and a width=0 loan/credit leg sized to neutralize it. |
|
|
60
|
-
| `advise_position` | Live facts + management advice for a position (ITM/OTM, streamia, closeable-now, liquidation risk). |
|
|
67
|
+
| `advise_position` | Live facts + management advice for a position (ITM/OTM, streamia (streaming premium), closeable-now, liquidation risk). |
|
|
61
68
|
| `preview_position` | Pre-trade quote (dry-run `eth_call`): collateral required, post-mint balances, solvency, for a given tokenId + size. |
|
|
62
69
|
| `position_scenario` | Payoff / NLV curve — net liquidation value across a band of hypothetical prices. |
|
|
63
70
|
| `hedge_params` | SDK-native delta-hedge parameters (`getDeltaHedgeParams`) to reach a target delta; whole-portfolio or single-position. |
|
|
@@ -100,7 +107,7 @@ pnpm --filter @panoptic-eng/mcp typecheck # tsc --noEmit
|
|
|
100
107
|
pnpm --filter @panoptic-eng/mcp lint
|
|
101
108
|
|
|
102
109
|
# Inspect locally against a real RPC:
|
|
103
|
-
PANOPTIC_RPC_URL
|
|
110
|
+
PANOPTIC_RPC_URL=<RPC URL> PANOPTIC_CHAIN_ID=1 \
|
|
104
111
|
npx @modelcontextprotocol/inspector node dist/cli.js
|
|
105
112
|
```
|
|
106
113
|
|
package/dist/cli.js
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
-
import { SERVER_VERSION, createContext, createServer, resolveConfig } from "./server-
|
|
2
|
+
import { SERVER_VERSION, createContext, createServer, resolveConfig } from "./server-DB4yvrb5.js";
|
|
3
3
|
import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
|
|
4
|
+
import { redactRpcSecrets } from "@panoptic-eng/sdk/rpc";
|
|
4
5
|
|
|
5
6
|
//#region src/cli.ts
|
|
6
7
|
async function main() {
|
|
@@ -13,7 +14,7 @@ async function main() {
|
|
|
13
14
|
}
|
|
14
15
|
main().catch((err) => {
|
|
15
16
|
const message = err instanceof Error ? err.message : String(err);
|
|
16
|
-
console.error(`panoptic-mcp failed to start: ${message}`);
|
|
17
|
+
console.error(`panoptic-mcp failed to start: ${redactRpcSecrets(message)}`);
|
|
17
18
|
process.exit(1);
|
|
18
19
|
});
|
|
19
20
|
|
package/dist/index.d.ts
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
/// <reference types="node" />
|
|
2
|
+
import { RpcEndpoint } from "@panoptic-eng/sdk/rpc";
|
|
2
3
|
import { ChainDeployment } from "@panoptic-eng/sdk/v2";
|
|
3
4
|
import { Address, Hex, PublicClient } from "viem";
|
|
4
5
|
import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
|
|
@@ -11,7 +12,10 @@ declare const KNOWN_CHAIN_IDS: readonly [1, 11155111];
|
|
|
11
12
|
*/
|
|
12
13
|
|
|
13
14
|
interface ServerConfig {
|
|
15
|
+
/** Primary RPC URL; used alone when `rpcEndpoints` is absent. */
|
|
14
16
|
rpcUrl: string;
|
|
17
|
+
/** RPC endpoints for `chainId`, primary first, with their credential headers. */
|
|
18
|
+
rpcEndpoints?: RpcEndpoint[];
|
|
15
19
|
chainId: number;
|
|
16
20
|
/** Optional indexer URL; enables enhanced analytics tools. */
|
|
17
21
|
subgraphUrl?: string;
|
|
@@ -38,9 +42,11 @@ interface PanopticContext {
|
|
|
38
42
|
}
|
|
39
43
|
/**
|
|
40
44
|
* Resolve server config from CLI flags (`--rpc-url`, `--chain-id`,
|
|
41
|
-
* `--subgraph-url`) layered over env (`
|
|
42
|
-
* `PANOPTIC_SUBGRAPH_URL`). CLI flags win.
|
|
43
|
-
*
|
|
45
|
+
* `--subgraph-url`) layered over env (`PANOPTIC_CHAIN_ID`,
|
|
46
|
+
* `PANOPTIC_SUBGRAPH_URL`). CLI flags win. `--rpc-url` is used as-is; otherwise
|
|
47
|
+
* the RPC resolves from `RPC_URL_<chainId>`, `PANOPTIC_RPC_URL` or a provider
|
|
48
|
+
* key (docs/rpc.md). Throws a readable error when the RPC or chain id is
|
|
49
|
+
* missing or unsupported.
|
|
44
50
|
*/
|
|
45
51
|
declare function resolveConfig(argv: string[], env: NodeJS.ProcessEnv): ServerConfig;
|
|
46
52
|
/** Create the shared context (viem client + resolved deployment) for tools. */
|
package/dist/index.js
CHANGED
|
@@ -1,3 +1,3 @@
|
|
|
1
|
-
import { KNOWN_CHAIN_IDS, SERVER_NAME, SERVER_VERSION, buildEnvelope, createContext, createServer, jsonResult, resolveConfig, toJsonSafe } from "./server-
|
|
1
|
+
import { KNOWN_CHAIN_IDS, SERVER_NAME, SERVER_VERSION, buildEnvelope, createContext, createServer, jsonResult, resolveConfig, toJsonSafe } from "./server-DB4yvrb5.js";
|
|
2
2
|
|
|
3
3
|
export { KNOWN_CHAIN_IDS, SERVER_NAME, SERVER_VERSION, buildEnvelope, createContext, createServer, jsonResult, resolveConfig, toJsonSafe };
|
|
@@ -1,5 +1,6 @@
|
|
|
1
|
+
import { resolveRpcEndpoints, rpcTransport } from "@panoptic-eng/sdk/rpc";
|
|
1
2
|
import { DEFAULT_VEGOID, MAX_TICK, MIN_TICK, STANDARD_TICK_WIDTHS, WAD, createMemoryStorage, createTokenIdBuilder, decodeTokenId, getAccountBuyingPower, getAccountCollateral, getAccountGreeks, getAccountHistory, getAccountPremia, getChainDeployment, getDeltaHedgeParams, getLegDelta, getMarginBuffer, getNetLiquidationValues, getOpenPositionPreview, getPool, getPoolDeploymentBlock, getPoolLiquidities, getPositions, getTrackedPositionIds, hasLoanOrCredit, hasLongLeg, isCall, isCreditLeg, isLiquidatable, isLoanLeg, isShortOnly, isSpread, roundToTickSpacing, scanChunks, simulateClosePosition, syncPositions, tickToPriceDecimalScaled } from "@panoptic-eng/sdk/v2";
|
|
2
|
-
import { createPublicClient, getAddress,
|
|
3
|
+
import { createPublicClient, getAddress, isAddress, keccak256, toBytes, toHex } from "viem";
|
|
3
4
|
import { mainnet, sepolia } from "viem/chains";
|
|
4
5
|
import { createRequire } from "node:module";
|
|
5
6
|
import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
|
|
@@ -35,14 +36,14 @@ function resolveChainId(rawChainId, fallback) {
|
|
|
35
36
|
var ConfigError = class extends Error {};
|
|
36
37
|
/**
|
|
37
38
|
* Resolve server config from CLI flags (`--rpc-url`, `--chain-id`,
|
|
38
|
-
* `--subgraph-url`) layered over env (`
|
|
39
|
-
* `PANOPTIC_SUBGRAPH_URL`). CLI flags win.
|
|
40
|
-
*
|
|
39
|
+
* `--subgraph-url`) layered over env (`PANOPTIC_CHAIN_ID`,
|
|
40
|
+
* `PANOPTIC_SUBGRAPH_URL`). CLI flags win. `--rpc-url` is used as-is; otherwise
|
|
41
|
+
* the RPC resolves from `RPC_URL_<chainId>`, `PANOPTIC_RPC_URL` or a provider
|
|
42
|
+
* key (docs/rpc.md). Throws a readable error when the RPC or chain id is
|
|
43
|
+
* missing or unsupported.
|
|
41
44
|
*/
|
|
42
45
|
function resolveConfig(argv, env) {
|
|
43
46
|
const flags = parseFlags(argv);
|
|
44
|
-
const rpcUrl = flags["rpc-url"] ?? env.PANOPTIC_RPC_URL;
|
|
45
|
-
if (!rpcUrl) throw new ConfigError("Missing RPC URL. Set PANOPTIC_RPC_URL or pass --rpc-url <url>.");
|
|
46
47
|
const rawChainId = flags["chain-id"] ?? env.PANOPTIC_CHAIN_ID;
|
|
47
48
|
if (!rawChainId) throw new ConfigError("Missing chain id. Set PANOPTIC_CHAIN_ID or pass --chain-id <id>.");
|
|
48
49
|
let chainId;
|
|
@@ -52,22 +53,42 @@ function resolveConfig(argv, env) {
|
|
|
52
53
|
throw new ConfigError(err instanceof Error ? err.message : String(err));
|
|
53
54
|
}
|
|
54
55
|
const subgraphUrl = flags["subgraph-url"] ?? env.PANOPTIC_SUBGRAPH_URL ?? void 0;
|
|
56
|
+
const rpcEndpoints = resolveRpc(flags["rpc-url"], chainId, env);
|
|
55
57
|
return {
|
|
56
|
-
rpcUrl,
|
|
58
|
+
rpcUrl: rpcEndpoints[0].url,
|
|
59
|
+
rpcEndpoints,
|
|
57
60
|
chainId,
|
|
58
61
|
subgraphUrl
|
|
59
62
|
};
|
|
60
63
|
}
|
|
64
|
+
function resolveRpc(rpcUrlFlag, chainId, env) {
|
|
65
|
+
if (rpcUrlFlag) return [{
|
|
66
|
+
source: "url",
|
|
67
|
+
url: rpcUrlFlag,
|
|
68
|
+
headers: {}
|
|
69
|
+
}];
|
|
70
|
+
try {
|
|
71
|
+
return resolveRpcEndpoints(chainId, env, { legacyUrlEnv: ["PANOPTIC_RPC_URL"] });
|
|
72
|
+
} catch (err) {
|
|
73
|
+
const message = err instanceof Error ? err.message : String(err);
|
|
74
|
+
if (!message.startsWith("No RPC configured")) throw new ConfigError(message);
|
|
75
|
+
throw new ConfigError(`Missing RPC URL. ${message}, or pass --rpc-url <url>.`);
|
|
76
|
+
}
|
|
77
|
+
}
|
|
61
78
|
/** Create the shared context (viem client + resolved deployment) for tools. */
|
|
62
79
|
async function createContext(config) {
|
|
63
80
|
const deployment = getChainDeployment(config.chainId);
|
|
64
81
|
if (deployment === void 0) throw new ConfigError(`Unsupported chain id ${config.chainId}`);
|
|
65
82
|
const client = createPublicClient({
|
|
66
83
|
chain: VIEM_CHAINS[config.chainId],
|
|
67
|
-
transport:
|
|
84
|
+
transport: rpcTransport(config.rpcEndpoints ?? [{
|
|
85
|
+
source: "url",
|
|
86
|
+
url: config.rpcUrl,
|
|
87
|
+
headers: {}
|
|
88
|
+
}])
|
|
68
89
|
});
|
|
69
90
|
const rpcChainId = await client.getChainId();
|
|
70
|
-
if (rpcChainId !== config.chainId) throw new ConfigError(`RPC chain id ${rpcChainId} does not match configured chain id ${config.chainId}. Point
|
|
91
|
+
if (rpcChainId !== config.chainId) throw new ConfigError(`RPC chain id ${rpcChainId} does not match configured chain id ${config.chainId}. Point the RPC at a chain-${config.chainId} endpoint or set PANOPTIC_CHAIN_ID to ${rpcChainId}.`);
|
|
71
92
|
return {
|
|
72
93
|
config,
|
|
73
94
|
client,
|
|
@@ -519,8 +540,8 @@ function registerAdvisePosition(server, ctx) {
|
|
|
519
540
|
if (closeable === false) recommendations.push(`This position cannot be closed at the moment${closeBlockedReason ? ` (${closeBlockedReason.name})` : ""}. For a long leg this usually means the in-range liquidity needed to unwind it has been withdrawn — check chunk_spread / liquidity_map and retry when liquidity returns; otherwise the pool may be in a restricted safety mode.`);
|
|
520
541
|
for (const leg of legs) {
|
|
521
542
|
if (leg.kind === "loan" || leg.kind === "credit") continue;
|
|
522
|
-
if (leg.side === "short" && leg.moneyness === "ITM") recommendations.push(`Leg ${leg.index}: your short ${leg.kind} is ITM (price moved through strike ${leg.strike}).
|
|
523
|
-
else if (leg.side === "long" && leg.inRange === false) recommendations.push(`Leg ${leg.index}: your long ${leg.kind} is out-of-range/OTM. It
|
|
543
|
+
if (leg.side === "short" && leg.moneyness === "ITM") recommendations.push(`Leg ${leg.index}: your short ${leg.kind} is ITM (price moved through strike ${leg.strike}). Short legs earn streamia while in range and carry pin/assignment risk — consider rolling the strike out or closing if you don't want continued directional exposure.`);
|
|
544
|
+
else if (leg.side === "long" && leg.inRange === false) recommendations.push(`Leg ${leg.index}: your long ${leg.kind} is out-of-range/OTM. It does not accrue streamia while out of range, and out-of-range longs can be force-exercised by others — consider closing to reclaim capital.`);
|
|
524
545
|
}
|
|
525
546
|
return jsonResult({
|
|
526
547
|
tokenId: id,
|
|
@@ -542,7 +563,7 @@ function registerAdvisePosition(server, ctx) {
|
|
|
542
563
|
shortPremium1: premia.shortPremium1,
|
|
543
564
|
longPremium0: premia.longPremium0,
|
|
544
565
|
longPremium1: premia.longPremium1,
|
|
545
|
-
note: "shortPremium = streamia earned by short legs; longPremium = streamia
|
|
566
|
+
note: "shortPremium = accrued streamia earned by short legs; longPremium = accrued streamia owed by long legs (token0/token1)."
|
|
546
567
|
},
|
|
547
568
|
health: {
|
|
548
569
|
isLiquidatable: liquidation.isLiquidatable,
|
|
@@ -599,7 +620,7 @@ function toMultiplier(spreadWad) {
|
|
|
599
620
|
function registerChunkSpread(server, ctx) {
|
|
600
621
|
server.registerTool("chunk_spread", {
|
|
601
622
|
title: "Chunk spread multipliers",
|
|
602
|
-
description: "Per-chunk spread multiplier across a tick range of the configured pool, via the SDK's scanChunks. The spread multiplier is the
|
|
623
|
+
description: "Per-chunk spread multiplier across a tick range of the configured pool, via the SDK's scanChunks. The spread multiplier is the streamia multiplier applied to a chunk: 1.0x means no liquidity has been removed (lowest implied vol) — those chunks are the CHEAPEST to BUY. A higher multiplier means more liquidity is already utilized, so the chunk pays a richer streamia — those chunks are the most PROFITABLE to SELL. Reported per token type (0 and 1). Chunk width defaults to a standard timescale width (1H/1D/1W/1M/1Y ≈ ±1%/±4%/±13%/±27%/±112% price range).",
|
|
603
624
|
inputSchema: {
|
|
604
625
|
timescale: z.enum([
|
|
605
626
|
"1H",
|
|
@@ -667,9 +688,9 @@ function registerChunkSpread(server, ctx) {
|
|
|
667
688
|
lower,
|
|
668
689
|
upper
|
|
669
690
|
},
|
|
670
|
-
interpretation: "spreadMultiplier is the
|
|
691
|
+
interpretation: "spreadMultiplier is the streamia multiplier for the chunk. 1.0x = no liquidity removed (lowest IV) → cheapest to BUY. Higher = more liquidity utilized → richer streamia → most profitable to SELL. token0/token1 suffixes are the two token types (put vs call side).",
|
|
671
692
|
recommendation: {
|
|
672
|
-
sellHere: bestForSelling.length ? bestForSelling : "No chunk currently carries a spread multiplier above 1.0x (no removed liquidity) — selling earns only the base
|
|
693
|
+
sellHere: bestForSelling.length ? bestForSelling : "No chunk currently carries a spread multiplier above 1.0x (no removed liquidity) — selling earns only the base streamia everywhere in range.",
|
|
673
694
|
buyHere: bestForBuying
|
|
674
695
|
},
|
|
675
696
|
chunkCount: rows.length,
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@panoptic-eng/mcp",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.35",
|
|
4
4
|
"description": "Local MCP server exposing the Panoptic SDK as read/build/simulate tools for AI agents.",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"type": "module",
|
|
@@ -35,7 +35,7 @@
|
|
|
35
35
|
},
|
|
36
36
|
"dependencies": {
|
|
37
37
|
"@modelcontextprotocol/sdk": "^1.25.0",
|
|
38
|
-
"@panoptic-eng/sdk": "^1.0.
|
|
38
|
+
"@panoptic-eng/sdk": "^1.0.63",
|
|
39
39
|
"viem": "^2.41.2",
|
|
40
40
|
"zod": "^4.3.6"
|
|
41
41
|
},
|