@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 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": "https://eth-mainnet.g.alchemy.com/v2/<key>",
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 https://eth-mainnet.g.alchemy.com/v2/<key> --chain-id 1
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=https://eth-mainnet.g.alchemy.com/v2/<key> PANOPTIC_CHAIN_ID=1 \
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-CabyB7Fb.js";
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 (`PANOPTIC_RPC_URL`, `PANOPTIC_CHAIN_ID`,
42
- * `PANOPTIC_SUBGRAPH_URL`). CLI flags win. Throws a readable error when RPC URL
43
- * or chain id is missing or unsupported.
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-CabyB7Fb.js";
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, http, isAddress, keccak256, toBytes, toHex } from "viem";
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 (`PANOPTIC_RPC_URL`, `PANOPTIC_CHAIN_ID`,
39
- * `PANOPTIC_SUBGRAPH_URL`). CLI flags win. Throws a readable error when RPC URL
40
- * or chain id is missing or unsupported.
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: http(config.rpcUrl)
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 PANOPTIC_RPC_URL at a chain-${config.chainId} endpoint or set PANOPTIC_CHAIN_ID to ${rpcChainId}.`);
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}). You are paying out streamia and carry pin/assignment risk — consider rolling the strike out or closing if you don't want continued directional exposure.`);
523
- else if (leg.side === "long" && leg.inRange === false) recommendations.push(`Leg ${leg.index}: your long ${leg.kind} is out-of-range/OTM. It is decaying (you pay streamia) and out-of-range longs can be force-exercised by others — consider closing to reclaim capital.`);
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 paid by long legs (token0/token1)."
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 premium 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 premium — 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).",
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 premium multiplier for the chunk. 1.0x = no liquidity removed (lowest IV) → cheapest to BUY. Higher = more liquidity utilized → richer premium → most profitable to SELL. token0/token1 suffixes are the two token types (put vs call side).",
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 premium everywhere in range.",
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.33",
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.61",
38
+ "@panoptic-eng/sdk": "^1.0.63",
39
39
  "viem": "^2.41.2",
40
40
  "zod": "^4.3.6"
41
41
  },