@battlegrid/mcp-server 31.2.26 → 31.2.28

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
@@ -24,6 +24,62 @@ Seeing package `31.x` alongside handshake `battlegrid@33.x` — the package **be
24
24
 
25
25
  **What this changes for you:** nothing about how you call anything. Upgrading the package no longer waits on a server deploy, and a server deploy no longer strands you on a package that names the wrong contract — reconnect and the announcement follows. **Contract breaking-change notes are no longer keyed to package versions**, since a contract move is no longer a release here; the v11-and-earlier notes below are kept as history, and the live vocabulary is always discovery.
26
26
 
27
+ ## Contract history — v61
28
+
29
+ One part to read first: **the per-condition evidence clock is gone**, and what replaced it is not a
30
+ rename. Which bar a condition reads is now decided by the surface asking — a decision reads completed
31
+ strategy bars, a display read shows the forming one — and by each candle column's own Confirmed /
32
+ Developing selector. `closes` survives and changes meaning. The canonical record for every contract
33
+ move is `docs/architecture/MCP_CONTRACT_HISTORY.md` in `battlegrid-app`; the served version is what
34
+ the handshake announces.
35
+
36
+ ### Rejected input — something you author is no longer accepted
37
+
38
+ - **A condition entry carrying `clock` is REFUSED** (61.0.0, `read-higher-timeframes-per-column`).
39
+ The authoring schemas are `.strict()`, so `compile_strategy_plan`, `apply_strategy_plan`,
40
+ `fork_strategy` and the HTTP save alike fail the body with the unknown-key error. There is no
41
+ replacement key to send: the decision instant belongs to the caller, not to the condition. Two
42
+ input hashes move, `compile_strategy_plan`'s and `preview_strategy_report`'s — the two tools that
43
+ accept a condition entry.
44
+
45
+ - **`closes` stays mandatory and means something new.** It is now *held for N completed strategy
46
+ bars* (1–5). Above `1` it is legal only over a header a completed bar actually moves, at or above
47
+ the strategy timeframe, never over a developing read, and only where the condition carries a clause
48
+ of its own — a referenced condition resolves once and contributes the same answer to every bar, so
49
+ a hold reached only through a reference would count reads that never happened.
50
+
51
+ ### Changed shape — what you receive moves
52
+
53
+ - **`ConditionOutcome.closeClock` becomes `hold`, and it is NON-NULL for every condition.** A
54
+ one-close condition reads `0 or 1 of 1` rather than serving an absence, so a client no longer
55
+ branches on whether the reading exists. The count is taken from completed strategy bars whatever
56
+ basis the surface evaluated on.
57
+
58
+ - **`ReportConditionColumnDTO.closeClockReadable` becomes `closesReadable`, beside a new
59
+ `developingRead`.** The first answers whether a condition addressing that header may hold more than
60
+ one completed bar; the second states whether the header reads the bar still in progress at the
61
+ decision instant. Both are server-supplied — derive neither. Eight output hashes move, covering
62
+ every tool that serves a strategy's conditions or a report's addressable columns.
63
+
64
+ ### Wider input — nothing you send today breaks
65
+
66
+ - **The `bars` selector is declared on eleven candle-series transforms, not four.** `value`,
67
+ `classifyZone`, `classifyState`, `distance`, `spread`, `crossDetect` and `bandTouch` join
68
+ `trajectory`, `aggregate`, `efficiency` and `maxShare`. It carries **no default value**, because
69
+ the default is a rule rather than a constant: Confirmed (`"closed"`) above the strategy timeframe,
70
+ and at or below it the series as the frame carries it. The resolved answer is served per column on
71
+ `effectiveParameters.bars` — `null` where discovery has no anchor to resolve a rung against.
72
+
73
+ - **A higher-timeframe level is measured from the current strategy-bar price.** Distances and the
74
+ candle label classifiers compare against the frame's current price rather than the higher-timeframe
75
+ bar's own close, which could be a full higher-timeframe bar stale. A distance chained into a series
76
+ keeps every slot on its own bar's close.
77
+
78
+ ### Vocabulary
79
+
80
+ `domains.conditionClock` is removed; `domains.columnBars: ["all", "closed"]` takes its place, and
81
+ `axes.condition` loses `clock`. `toolCount` stays 117.
82
+
27
83
  ## Contract history — v60
28
84
 
29
85
  One release train, four numbers, and two parts to read first: **`propose_entry_decision` no longer
package/dist/index.d.ts CHANGED
@@ -49,7 +49,7 @@ import { type Implementation, type Prompt, type Resource } from '@modelcontextpr
49
49
  * being asked. Move it for a change to THIS package — a proxy fix, a dependency bump, a docs
50
50
  * correction. Never move it to track the server.
51
51
  */
52
- export declare const PACKAGE_VERSION = "31.2.26";
52
+ export declare const PACKAGE_VERSION = "31.2.28";
53
53
  export declare const DEFAULT_URL = "https://mcp.battlegrid.trade/mcp";
54
54
  export interface EnvConfig {
55
55
  apiKeys: string[];
package/dist/index.js CHANGED
@@ -52,7 +52,7 @@ import { ListToolsRequestSchema, CallToolRequestSchema, ListPromptsRequestSchema
52
52
  * being asked. Move it for a change to THIS package — a proxy fix, a dependency bump, a docs
53
53
  * correction. Never move it to track the server.
54
54
  */
55
- export const PACKAGE_VERSION = '31.2.26';
55
+ export const PACKAGE_VERSION = '31.2.28';
56
56
  export const DEFAULT_URL = 'https://mcp.battlegrid.trade/mcp';
57
57
  const MAX_RETRIES = 3;
58
58
  const RETRY_DELAYS_MS = [2000, 4000, 8000];
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@battlegrid/mcp-server",
3
- "version": "31.2.26",
3
+ "version": "31.2.28",
4
4
  "description": "BattleGrid MCP server — play crypto prediction games from AI agents",
5
5
  "type": "module",
6
6
  "main": "dist/index.js",
@@ -1,18 +1,18 @@
1
1
  {
2
2
  "generator": "battlegrid-app/server/scripts/export-mcp-skills.mjs",
3
- "contractVersion": "60.3.0",
3
+ "contractVersion": "61.0.1",
4
4
  "files": {
5
5
  "battlegrid-agent-management/SKILL.md": "b6ea75b3d838c1dbaaf3984d7e99a11c81686de2c1a1910c35699ee7e70dafa5",
6
6
  "battlegrid-arena-play/SKILL.md": "03fa153bf82be18bf5ed01e3ba12e2cd9f99a81b08d903a77b52169e7519a182",
7
7
  "battlegrid-market-analysis/SKILL.md": "22fde9c4eac0261c89a8056ab8b20b66fcbe1fd58447fa0ac84fd410b4d134d7",
8
8
  "battlegrid-radar-deployment/SKILL.md": "d2a012b154e1e529db19529bd7c3d75d069f4e410d5804add51165f0f0902b2e",
9
- "battlegrid-strategy-authoring/SKILL.md": "ea2593ea9d6d2feb9910e285e4b132eb36001164b9d6551cc206531afad3f552",
9
+ "battlegrid-strategy-authoring/SKILL.md": "93e1c9709079a4e9c968597ac572b4b62f5b0e68c01f9e9947db7e2ba304dcdf",
10
10
  "battlegrid-strategy-doctor/SKILL.md": "9ab3f79128ec81d3e90167c3f1ea4bd6f6b570290e5ebe2bf855195263c58239",
11
- "battlegrid-strategy-examples/SKILL.md": "263c3b865ea85e56ac420611a7070360d65be6f2faee071329880e49a6101eda",
11
+ "battlegrid-strategy-examples/SKILL.md": "17e8cf8040813622bd5b82165c7af82e03287fee1f6aac974e0b6c584580dd27",
12
12
  "battlegrid-strategy-examples/references/playbooks.md": "35c543c090d00ba19e4bcf0a80502afac7a4954643fc535de0b24381c91ecbf4",
13
13
  "battlegrid-strategy-examples/references/recipes.md": "53887daece17995543e7d3fe1bf2577fc41a6254c291acacde48d7de63853641",
14
14
  "battlegrid-strategy-examples/references/tradingview-ports.md": "2b13adbc137178955edcca31b6ab40c01c745a932a0750b91db8820c736700bb",
15
15
  "battlegrid-trade-analysis/SKILL.md": "32573a67e55d735e6ee4e36b3b48c815694102704bc453c4d1c13db39551b3da",
16
- "battlegrid-trade-proposal/SKILL.md": "503ed705d4f9823e21846afe5a10f35d7d6e35933c4bdd1d5b4fd923eb9d674d"
16
+ "battlegrid-trade-proposal/SKILL.md": "0d8ffecd493f7916d352cee3d22aee5812c3790592b100d3f9802c75ca1180c0"
17
17
  }
18
18
  }
@@ -104,9 +104,9 @@ question you would otherwise guess — and a refusal you would otherwise earn:
104
104
  `levelOffsetAtrMultiple`, `validForBars`. Every trigger is decided at the close of the strategy's
105
105
  OWN bar, so there is no confirm-timeframe key; for the level triggers the level itself is derived
106
106
  from the trigger and the trade's direction, never named. A multi-bar hold belongs to the condition
107
- that needs it (`clock: CLOSE` with its own `closes`), not to this axis. The `strategy-examples`
108
- skill carries the vocabulary and the one-directional legality matrix; a CREATE without it is
109
- refused outright.
107
+ that needs it (its own `closes`, counted in completed strategy bars), not to this axis. The
108
+ `strategy-examples` skill carries the vocabulary, the hold's legality and the per-column
109
+ Confirmed / Developing read; a CREATE without it is refused outright.
110
110
  - `get_strategy_column_contract` → `outputs[].conditionOperators`. An empty array means that
111
111
  rendered header has no comparison semantics and cannot appear in a condition clause at all.
112
112
  Legality is per rendered header, not per column: a trajectory's slot header and its `_trend`
@@ -86,8 +86,9 @@ against a literal; neither of those shapes is what a previous-session level need
86
86
 
87
87
  ## Conditions
88
88
 
89
- `{ conditionKey, name, definition, verdict, required, exit, clock, closes }` — all eight
90
- required, no defaults. Clauses: numeric/rank headers take `lt|lte|gte|gt|between`;
89
+ `{ conditionKey, name, definition, verdict, required, exit, closes }` — all seven
90
+ required, no defaults. A `clock` key is REFUSED: the per-condition evidence clock was retired in
91
+ contract `61.0.0`. Clauses: numeric/rank headers take `lt|lte|gte|gt|between`;
91
92
  classification/direction headers take `is|in` with the served vocabulary. Groups:
92
93
  `ALL | ANY | NOT | N_OF` (with `n`), depth ≤ 2. `conditionRef` composes named conditions (no
93
94
  cycles; forward refs legal). `sectionKey: null` is sugar for a report-unique header only.
@@ -103,30 +104,53 @@ before billing. And the RESOLVED verdict binds entry DIRECTION: `UP` admits long
103
104
  setups block and from the `decide_trade` contract, not merely discouraged in them. A strategy that
104
105
  declares no verdict-carrying condition resolves `null` and constrains nothing.
105
106
 
106
- A verdict carrier must read a SETTLED bar wherever one is available to it — `clock: "CLOSE"`
107
- whenever every column in its CLOSURE accepts a closed frame. The closure is what it reads directly
108
- plus everything reached through `conditionRef`, transitively: a referenced condition contributes what
109
- IT reads, never the clock it happens to declare, so moving a clause into a building block and leaving
110
- that block `LIVE` does not make a settled bar unavailable to the carrier. Where no closed frame moves
111
- some operand in the closure (a published regime label, an open-interest regime, a published rolling
112
- change), `LIVE` stays legal at any depth: there is no settled bar to take.
113
-
114
- Evaluation is three-valued: UNRESOLVED never collapses to FALSE; forming-bar reads are provisional.
115
-
116
- **The evidence clock.** `clock: "LIVE"` reads the forming bar; `clock: "CLOSE"` reads settled
117
- bars, and `closes` is how many consecutive closed bars must read TRUE (1–5) — always `1` under
118
- LIVE, which has exactly one frame. A CLOSE clock is legal **only** over a header resolved from
119
- this coin's own candle series at offset 0. Frame-inert operands are refused
120
- (`CONDITION_CLOCK_OPERAND_ILLEGAL`): perp-payload scalars, published rolling changes, ranks, zone
121
- entities, MDS regime labels, enrichment metrics, session scalars, and any clause authored at a
122
- non-zero offset. A closed frame cannot move them, so "held for N closes" would describe reads
123
- that never happened. A frame-inert operand anywhere in a condition's closure simply keeps that
124
- condition on `LIVE`, and that is legal — splitting the clause into its own condition and
125
- `conditionRef`-ing it does NOT buy the referencing condition a CLOSE clock, because a `CLOSE`
126
- condition may not reference a `LIVE` one (`CONDITION_CLOCK_REFERENCE_ILLEGAL`) and availability walks
127
- into the referenced closure anyway. **Worked liquidity floor:** `LIQUID_FLOOR` is `LIVE` because
128
- `vol24hUsd` is a bundle scalar, and a condition that references it is `LIVE` too. Reach for a split to
129
- keep a condition's MEANING separable, not to change its clock.
107
+ A verdict carrier must read no DEVELOPING bar. A verdict is refused over any closure that reads a
108
+ column selecting Developing above the strategy timeframe (`CONDITION_VERDICT_READ_ILLEGAL`). The
109
+ closure is what the condition reads directly plus everything reached through `conditionRef`,
110
+ transitively: a referenced condition contributes what IT reads, so moving the clause into a building
111
+ block does not launder it. A closure whose candle columns all read Confirmed — or whose operands no
112
+ bar moves at all, such as a published regime label, an open-interest regime or a published rolling
113
+ change — admits a verdict at every decision, because a decision reads the completed strategy bar and
114
+ a level is compared against that bar's close.
115
+
116
+ Evaluation is three-valued: UNRESOLVED never collapses to FALSE; a developing read is provisional,
117
+ and so is any reading taken on the display lane's forming bar.
118
+
119
+ **Every condition is decided at the strategy bar's close.** There is no per-condition clock. Which
120
+ bar a condition reads is decided by the surface asking — a decision (the radar's close decision, the
121
+ compose that takes the trade, the exit sweep) reads completed strategy bars; a display read shows the
122
+ forming one and decides nothing — and by each candle column's own Confirmed / Developing selector.
123
+
124
+ **The hold count.** `closes` is how many consecutive COMPLETED strategy bars must read TRUE (1–5). A
125
+ hold counts the same completed bars whichever surface asks, so a held condition reads them on the
126
+ display lane too. Above `1` it is legal **only** where a completed bar changes the reading: over a
127
+ header resolved from this coin's own candle series, at offset 0, at or above the strategy timeframe,
128
+ read Confirmed. Everything else is refused (`CONDITION_HOLD_OPERAND_ILLEGAL`) — perp-payload scalars,
129
+ published rolling changes, ranks, zone entities, MDS regime labels, enrichment metrics, session
130
+ scalars, a non-zero offset, a column BELOW the strategy timeframe (the retained lower series cannot
131
+ reach an earlier strategy close), and a developing read (the bar in progress exists on the newest
132
+ frame only). A hold also needs a clause of the condition's OWN
133
+ (`CONDITION_HOLD_ILLEGAL`): a referenced condition is resolved once and contributes the same answer
134
+ to every frame, so a hold that moves with the bar only through a reference would count reads that
135
+ never happened. **Worked liquidity floor:** `LIQUID_FLOOR` holds one close because `vol24hUsd` is a
136
+ bundle scalar. Reach for a split to keep a condition's MEANING separable, not to buy it a hold.
137
+
138
+ **Confirmed / Developing, per candle column.** Every transform whose home is the coin's candle series
139
+ carries `bars`: `"closed"` is Confirmed — the newest bar completed at the strategy close — and
140
+ `"all"` is Developing, the higher-timeframe bar still in progress at that close, which REPAINTS until
141
+ it completes. Left unset the default is a rule, not a value: Confirmed for a column ABOVE the
142
+ strategy timeframe, and at or below it the series as the frame carries it. At or below the strategy
143
+ timeframe the choice therefore sets only what the live lane shows — no bar is in progress at the
144
+ anchor's own close — so Developing there is legal and changes no decision. A condition reading a
145
+ developing bar is single-frame: it holds one close, carries no verdict and cannot take the `exit`
146
+ role. The resolved answer for a column is served on `effectiveParameters.bars`.
147
+
148
+ **A higher-timeframe level is measured from the current strategy-bar price.** The distance to a `4h`
149
+ Donchian band, and every candle label classifier (`MA_ALIGN`, `PRICE_ZONE`, `BB_TOUCH`), compares
150
+ against the frame's current price — the strategy bar's close under a decision, the live mark on
151
+ display — not against the higher-timeframe bar's own close, which is up to one higher-timeframe bar
152
+ stale. A distance CHAINED into a series transform keeps every slot on its own bar's close, so one
153
+ series carries one reference basis.
130
154
 
131
155
  **The lane a strategy is deployed to.** Report-level scalars split by LANE, and the split is not a
132
156
  quality of the header — it is which reader runs. Market breadth and the reference pairs are ordinary
@@ -138,10 +162,12 @@ can read instead. The refusal lands at DEPLOY rather than at save, because a str
138
162
  of its own: the same strategy is legal, and reads those scalars correctly, on an arena agent.
139
163
 
140
164
  **The exit role.** `exit: true` makes a settled TRUE reading close open positions its verdict
141
- opposes — UP exits SHORTs, DOWN exits LONGs, a NEITHER or `null` verdict exits both. Legal only
142
- under `clock: "CLOSE"`: a LIVE reading is the forming bar, and an exit fired on one is an
143
- intrabar exit. Orthogonal to `required` — the two act on disjoint lifecycles, pre-entry versus
144
- open — so a condition may carry both, either, or neither.
165
+ opposes — UP exits SHORTs, DOWN exits LONGs, a NEITHER or `null` verdict exits both. Legal only over
166
+ a closure every operand of which a completed bar MOVES (`CONDITION_EXIT_READ_ILLEGAL`), which rules
167
+ out a developing read — a bar in progress is the forming bar, and an exit fired on one is an intrabar
168
+ exit — and rules out a frame-inert operand, which could never fire. Orthogonal to `required` — the
169
+ two act on disjoint lifecycles, pre-entry versus open — so a condition may carry both, either, or
170
+ neither.
145
171
 
146
172
  **A state column is not a flip event.** `ST_DIR` reads the same on every bar of a trend, so
147
173
  `ST_DIR is "bullish"` is a regime filter and never an entry signal. The flip needs an event column
@@ -163,7 +189,7 @@ is DERIVED from the trigger and the trade's direction, never named. There is no
163
189
  key either: the bar whose close decides an entry is the strategy's OWN timeframe.
164
190
 
165
191
  **Every trigger is decided at the close of the strategy's own bar — there are three, and the close
166
- is the only entry clock.** The newest settled bar is read on the closed basis — every `LIVE`-clocked
192
+ is the only entry clock.** The newest completed bar is read on the closed basis — every one-close
167
193
  condition resolves on that bar and the scorecard reads its close — and a reading that still qualifies
168
194
  fires at that close. A bar that does not qualify decides nothing and is not revisited. The fill lands
169
195
  at the next tick, and the platform refuses it if the market has already run past its own drift budget
@@ -180,8 +206,8 @@ and is REFUSED on every save; there is no live-reading entry to author.
180
206
  short) by the offset, waiting for a return to it. Not filling is a correct outcome, not a
181
207
  failure; no unrecovered break in memory means no setup, never a fallback level.
182
208
 
183
- **A multi-bar hold belongs to the CONDITION that needs it.** Declare `clock: CLOSE` with that
184
- condition's own `closes` — the entry axis counts no bars, and there is no displacement band: the
209
+ **A multi-bar hold belongs to the CONDITION that needs it.** Declare that condition's own `closes` —
210
+ the entry axis counts no bars, and there is no displacement band: the
185
211
  platform's entry-deviation gate measures the live mark against the decided close and refuses a fill
186
212
  that drifted past the budget in either direction.
187
213
 
@@ -31,6 +31,15 @@ re-sorts a list, re-derives a verdict, or approves on the player's behalf.
31
31
 
32
32
  ## 2. Queue the request
33
33
 
34
+ **In a conversation the Agent Toolbox hosts, this section does not apply: name the coin and stop.**
35
+ The player presses **Request a trade** in the trade lane beside you and the same queued request is
36
+ registered from there, free and without a model turn; your job is to say which coin is worth
37
+ requesting and what the gates read, and to leave the press to them. `propose_entry_decision` and
38
+ `cancel_entry_request` are refused from such a conversation as tool errors, so calling one spends an
39
+ op of your budget and queues nothing. The refusal is **host-wide** — every tool that writes is
40
+ refused there, which is why no other skill carries a paragraph of its own — and every read in this
41
+ flow stays available.
42
+
34
43
  - `propose_entry_decision` **only** on the coins the player named, or on the top qualifying row
35
44
  when they asked for the best fit. One coin per call.
36
45
  - **The call does not decide.** It registers a request against the agent's next strategy-bar close
@@ -62,6 +71,13 @@ re-sorts a list, re-derives a verdict, or approves on the player's behalf.
62
71
 
63
72
  ## 4. When the answer arrives — approve or decline only on the player's word
64
73
 
74
+ **In a conversation the Agent Toolbox hosts, the approval is not yours to send.** The decided close
75
+ lands on the trade card in the lane beside you, carrying the player's own Accept and Decline;
76
+ `accept_entry_decision` and `cancel_entry_decision` are refused there as tool errors, so calling one
77
+ spends an op and moves nothing. Read the card back to them — the direction, the levels, the
78
+ conviction, the expiry — and say what you would do, which is the whole of your part. What you have
79
+ to work from is whatever the player attaches from a card: its rendered readings, nothing more.
80
+
65
81
  - A decided close produces one of: a PROPOSED decision awaiting approval; a no-trade with the
66
82
  reason and the next coins worth asking about; a close that did not qualify; a window that passed
67
83
  with no sweep; or a bar the agent's own radar deployment decided first and traded in full.