@battlegrid/mcp-server 4.0.0 → 5.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 CHANGED
@@ -7,11 +7,45 @@ MCP server for [BattleGrid](https://battlegrid.trade) — play crypto prediction
7
7
 
8
8
  It is a thin, authenticated **stdio proxy** to BattleGrid's remote MCP server (Stripe `@stripe/mcp` pattern — no business logic). It discovers tools, prompts, and resources live from the server and re-exposes them to local MCP clients (Claude Desktop, Claude Code, Cursor). Capabilities are always **discovered live** — this package never hardcodes the tool catalog.
9
9
 
10
- ## v4 — breaking major (strategy conditions)
10
+ ## v5 — breaking major (conditions/verdicts fusion)
11
11
 
12
- **v4 pairs with the BattleGrid server's MCP contract v4.0.0.** The package major tracks the server's wire contract, because the proxy announces `battlegrid@<package version>` in its own stdio handshake — the number a client reads has to be the contract it will actually reach. Upgrade the package and the server major together.
12
+ **v5 pairs with the BattleGrid server's MCP contract v5.0.0.** The package major tracks the server's wire contract, because the proxy announces `battlegrid@<package version>` in its own stdio handshake — the number a client reads has to be the contract it will actually reach. Upgrade the package and the server major together.
13
13
 
14
- - **`apply_strategy_plan` requires the conditions axis.** The plan post-state now carries required `conditions` and `conditionVerdicts`; a payload built from the v3 field list is rejected with `plan.conditions: Required`. **Add both fields to the projection you already build** — apply takes an allowlisted projection of `approvedPlan`, never the object itself (`diff`, `viability`, `mismatches`, `signalRules`, `creationSeed`, `proposedRevision`, `bindingImpact`, `authoringCatalogDigest` are all rejected as unknown keys, and so are the `postState` fields apply does not accept: `id`, `scope`, `systemKey`, `visibility`, `cadence`, `isActive`, `forkedFromStrategyId`). The exact field list is step 7 of **Strategy authoring (compile → review → apply)** below. Only a client that forwards post-state fields generically — stripping the derived keys rather than enumerating the kept ones — picks the axis up without an edit. The proxy itself is unchanged: it embeds no schemas, pins no contract version, and forwards `{ request }` verbatim.
14
+ - **`conditionVerdicts` no longer exists.** The verdict now rides the condition that decides it, and precedence is the conditions' own declaration order rather than a separate ordered map:
15
+
16
+ ```jsonc
17
+ // v4 — two parallel arrays joined by string key
18
+ {
19
+ "conditions": [ { "conditionKey": "UP_FADE", "name": "…", "definition": { /* … */ } } ],
20
+ "conditionVerdicts": [ { "when": "UP_FADE", "then": "UP" } ]
21
+ }
22
+
23
+ // v5 — one array; the verdict rides its condition
24
+ {
25
+ "conditions": [ { "conditionKey": "UP_FADE", "name": "…", "definition": { /* … */ }, "verdict": "UP" } ]
26
+ }
27
+ ```
28
+
29
+ `verdict` is **required and nullable**, never optional: a building block that decides nothing spells its absence as an explicit `null`, never by omitting the key. An omitted `verdict` is a rejected payload, not a defaulted one.
30
+
31
+ - **A submitted `conditionVerdicts` is REJECTED, not ignored.** Deliberately — a v4 client that forwards the retired field is told what replaced it instead of getting an anonymous unrecognized-key rejection:
32
+
33
+ > `conditionVerdicts` was retired in contract 5.0.0 — a condition now carries its own `verdict` (`UP` | `DOWN` | `NEITHER`, or `null` for a building block). Move each mapping onto the condition it named and resubmit.
34
+
35
+ - **The authorable verdict domain narrowed to three.** `conditionGrammar.verdicts` advertised `['UP','DOWN','NEITHER','UNRESOLVED']` and now advertises `['UP','DOWN','NEITHER']`. `UNRESOLVED` is an *evaluation outcome* — "a deciding condition could not be evaluated" — never an authored intent, so advertising it offered a value the schema then rejected. Any client mirroring the advertised enum into its own validation must narrow with it.
36
+
37
+ - **The evaluated per-coin verdict is nullable.** Resolution is first-TRUE-decides over the verdict-carrying conditions in declaration order, and its four outcomes are all distinct claims — collapsing any pair loses information a reader needs:
38
+
39
+ | Evaluated verdict | Means |
40
+ |---|---|
41
+ | `UP` / `DOWN` / `NEITHER` as a **decision** | The first verdict-carrying condition that resolved TRUE declared it |
42
+ | `NEITHER` as a **fallthrough** | Every verdict-carrying condition resolved FALSE |
43
+ | `UNRESOLVED` | No carrier fired and at least one could not be evaluated — "could not be read", not "read as no setup" |
44
+ | `null` | The strategy declares no verdict-carrying condition at all — it expresses no direction |
45
+
46
+ `null` is new in v5; it previously surfaced as `NEITHER`. A client that renders the verdict must handle it without collapsing it into `NEITHER`.
47
+
48
+ - **The proxy itself is unchanged.** It embeds no schemas, pins no contract version, and forwards `{ request }` verbatim, so the whole break lands on whatever builds the apply projection. Apply takes an allowlisted projection of `approvedPlan`, never the object itself (`diff`, `viability`, `mismatches`, `signalRules`, `creationSeed`, `proposedRevision`, `bindingImpact`, `authoringCatalogDigest` are rejected as unknown keys, and so are the `postState` fields apply does not accept: `id`, `scope`, `systemKey`, `visibility`, `cadence`, `isActive`, `forkedFromStrategyId`). The exact field list is step 5 of **Strategy authoring (compile → review → apply)** below. A client that forwards post-state fields generically — stripping the derived keys rather than enumerating the kept ones — picks the fusion up without an edit; one that enumerates the fields it copies must drop `conditionVerdicts` from that list.
15
49
 
16
50
  The v3 authoring contract below is unchanged and still current:
17
51
 
@@ -19,7 +53,7 @@ The v3 authoring contract below is unchanged and still current:
19
53
  - **`create_strategy` is retired.** Direct strategy creation no longer exists. Author strategies with the compile → review → apply workflow below, and bind them to agents at agent-creation time (`create_intelligence_agent({ …, strategyId })`). There is no alias, shim, or flat-payload fallback.
20
54
  - **Rediscover after deployment.** Publishing the package does **not** refresh a running proxy's cached capability snapshot. After the server cutover, restart/reconnect the proxy process and re-run `tools/list`, `prompts/list`, and `resources/list`.
21
55
 
22
- > Earlier majors: **v1.x** single/multi-account stdio proxy; **v2.0.0** moved the default `BATTLEGRID_API_URL` to the `/mcp` suffix; **v3.0.0** the strategy-authoring major. See [Rediscovery & versioning](#rediscovery--versioning).
56
+ > Earlier majors: **v1.x** single/multi-account stdio proxy; **v2.0.0** moved the default `BATTLEGRID_API_URL` to the `/mcp` suffix; **v3.0.0** the strategy-authoring major; **v4.0.0** made `conditions` and `conditionVerdicts` required on the apply post-state. See [Rediscovery & versioning](#rediscovery--versioning).
23
57
 
24
58
  ## Quick Start
25
59
 
@@ -198,7 +232,7 @@ Strategies are authored through one strict, whole-plan workflow. **Compilation w
198
232
  - **UPDATE** supplies at least one changed axis and `expectedRevision`.
199
233
  - **RESTORE** targets an owned inactive revision (with any repair axes).
200
234
  4. **Review before confirming.** Inspect the returned `approvedPlan` (complete post-state, proposed revision, diff, bound-agent impact, expiry) and `reviewContext` (column contracts, point-in-time report preview, open positions, quota/name admission). The plan token expires after five minutes; recompile after expiry or drift.
201
- 5. **Apply only the exact reviewed plan.** After explicit user approval, call `apply_strategy_plan({ request: { plan, planToken, confirm: true } })`. Build `plan` from the compiled `approvedPlan` by copying, byte-identical: `operation`; `postState.id` as `strategyId`; `expiresAt`; `expectedRevision` for UPDATE/RESTORE; `explicitRuleOverrides` as `rules`; and from `postState` — `name`, `description`, `tagline`, `timeframe`, `regimeAutoDerive`, `regimeTimeframe`, `marketReadText`, `sections` (including every generated `custom:` key), `conditions`, `conditionVerdicts`, `minAggregateScore`, `minRequiredCount`, `minAtrPct`. Send nothing else — the server re-derives the scorecard, diff, viability, mismatches, seed, revision, and bound-agent impact, and rejects `diff`, `viability`, `mismatches`, `signalRules`, `creationSeed`, `proposedRevision`, `bindingImpact`, `authoringCatalogDigest`, and `reviewContext` as unknown keys. Changed configuration propagates to every bound agent immediately.
235
+ 5. **Apply only the exact reviewed plan.** After explicit user approval, call `apply_strategy_plan({ request: { plan, planToken, confirm: true } })`. Build `plan` from the compiled `approvedPlan` by copying, byte-identical: `operation`; `postState.id` as `strategyId`; `expiresAt`; `expectedRevision` for UPDATE/RESTORE; `explicitRuleOverrides` as `rules`; and from `postState` — `name`, `description`, `tagline`, `timeframe`, `regimeAutoDerive`, `regimeTimeframe`, `marketReadText`, `sections` (including every generated `custom:` key), `conditions` (each carrying its own required, nullable `verdict`), `minAggregateScore`, `minRequiredCount`, `minAtrPct`. Send nothing else — the server re-derives the scorecard, diff, viability, mismatches, seed, revision, and bound-agent impact, and rejects `diff`, `viability`, `mismatches`, `signalRules`, `creationSeed`, `proposedRevision`, `bindingImpact`, `authoringCatalogDigest`, and `reviewContext` as unknown keys. `conditionVerdicts` is rejected too, with a message naming its replacement — the verdict belongs on the condition. Changed configuration propagates to every bound agent immediately.
202
236
 
203
237
  `update_strategy_signal_rule({ request })` is the thin, focused one-rule edit. In multi-account mode every one of these calls uses the `{ account, request }` sibling envelope.
204
238
 
@@ -228,7 +262,8 @@ Tools, prompts, and resources are **discovered live** from the connected server
228
262
  | 2.0.0 | Default `BATTLEGRID_API_URL` moved to the `/mcp` suffix |
229
263
  | 3.0.0 | Strategy-authoring major: strict `{ account, request }` authoring envelopes with strip-only-account routing, compile → review → apply workflow, strategy-bound agent creation, and removal of the retired `create_strategy` operation |
230
264
  | 3.0.1 | Docs only — `apply_strategy_plan` now takes `{ plan, planToken, confirm }` instead of `{ approvedPlan, … }`; the server re-derives every planner-derived field and rejects resubmitted ones as unknown keys. No proxy behavior change |
231
- | **4.0.0** | Realigns the package major with the server's MCP contract v4.0.0, which broke on the conditions axis: `apply_strategy_plan` requires `conditions` and `conditionVerdicts` on the plan post-state. No proxy code change — the version is the client-facing signal, and the proxy's handshake carries it |
265
+ | 4.0.0 | Realigns the package major with the server's MCP contract v4.0.0, which broke on the conditions axis: `apply_strategy_plan` requires `conditions` and `conditionVerdicts` on the plan post-state. No proxy code change — the version is the client-facing signal, and the proxy's handshake carries it |
266
+ | **5.0.0** | Pairs with the server's MCP contract v5.0.0, the conditions/verdicts fusion: `conditionVerdicts` is retired and rejected with a message naming its replacement, each condition carries a required nullable `verdict`, precedence is the conditions' declaration order, the advertised authorable verdict domain narrows to `UP`/`DOWN`/`NEITHER`, and the evaluated per-coin verdict is nullable. No proxy code change — the version is the client-facing signal, and the proxy's handshake carries it |
232
267
 
233
268
  ## Maintainer release procedure
234
269
 
@@ -257,7 +292,7 @@ Before tagging:
257
292
  Run from a clean `battlegrid-mcp` checkout, substituting the intended unused version:
258
293
 
259
294
  ```bash
260
- release_version=4.0.0
295
+ release_version=5.0.0
261
296
  release_tag="mcp-server@${release_version}"
262
297
 
263
298
  git fetch origin --tags
package/dist/index.d.ts CHANGED
@@ -32,7 +32,7 @@
32
32
  */
33
33
  import { Server } from '@modelcontextprotocol/sdk/server/index.js';
34
34
  import { Client } from '@modelcontextprotocol/sdk/client/index.js';
35
- export declare const VERSION = "4.0.0";
35
+ export declare const VERSION = "5.0.0";
36
36
  export declare const DEFAULT_URL = "https://mcp.battlegrid.trade/mcp";
37
37
  export interface EnvConfig {
38
38
  apiKeys: string[];
package/dist/index.js CHANGED
@@ -36,7 +36,7 @@ import { StdioServerTransport } from '@modelcontextprotocol/sdk/server/stdio.js'
36
36
  import { Client } from '@modelcontextprotocol/sdk/client/index.js';
37
37
  import { StreamableHTTPClientTransport } from '@modelcontextprotocol/sdk/client/streamableHttp.js';
38
38
  import { ListToolsRequestSchema, CallToolRequestSchema, ListPromptsRequestSchema, GetPromptRequestSchema, ListResourcesRequestSchema, ReadResourceRequestSchema, } from '@modelcontextprotocol/sdk/types.js';
39
- export const VERSION = '4.0.0';
39
+ export const VERSION = '5.0.0';
40
40
  export const DEFAULT_URL = 'https://mcp.battlegrid.trade/mcp';
41
41
  const MAX_RETRIES = 3;
42
42
  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": "4.0.0",
3
+ "version": "5.0.0",
4
4
  "description": "BattleGrid MCP server — play crypto prediction games from AI agents",
5
5
  "type": "module",
6
6
  "main": "dist/index.js",