WarEra MCP
Read-only WarEra MCP server — lets an AI look up live game facts (players, companies, countries, markets, battles, events) and answer questions about them; the 17 tools shown here are part of a 44-tool read-only suite.
Players — public profile and stats (
get_player), plus companies they own with product, location, workforce and production bonus (get_player_companies).Companies — single company details: output, location, workforce, normalized production bonus, optional region context (
get_company_overview).World — country facts/regions (
get_country_overview), region detail by id or exact name (get_region), and current war list plus active battles (get_country_wars).Market — latest global quoted price for one item (
get_market_price), visible buy/sell order book with optional depth estimate (search_market), and wage benchmark with matching work offers (get_work_market).Battles — search battles by country/active state (
search_battles), battle status with optional live round snapshot (get_battle), and battle leaderboards by damage or points for users, countries or MUs (get_battle_ranking).Events — bounded page of recent world events filtered by country or event type (
search_events).Safety traits — every tool is read-only, idempotent, non-destructive; credentials are optional and request-scoped via
player_context; results are bounded/paginated snapshots, not complete histories.
Click on "Deploy Server".
Wait a few minutes for the server to deploy. Once ready, it will show a "Started" state.
In the chat, type
@followed by the MCP server name and your instructions, e.g., "@WarEra MCPWhat is the current price of iron and how deep is the order book?"
That's it! The server will respond to your query, and you can continue using it as needed.
Here is a step-by-step guide with screenshots.
WarEra MCP
A read-only MCP server that lets an AI assistant look things up in the browser game WarEra — players, companies, countries, markets, battles, military units, equipment, governments, rankings, workers, transactions, events and articles — and answer questions about them in plain language.
⚠️ Unofficial project
This is an unofficial, community-made project. It is not affiliated with, endorsed by, sponsored by, or supported by the WarEra developers or publishers in any way. "WarEra" and related names belong to their respective owners.
It is a personal open-source hobby project, built in my free time with the help of AI. It uses WarEra's web API and its official documentation. API behavior and response shapes can change; documented requests are checked against live responses where possible. Please be considerate with the game's servers.
What is this?
MCP (Model Context Protocol) is a standard way to plug tools into AI assistants such as Claude Desktop. This server gives an assistant purpose-built, game-aware tools instead of raw web requests, so you can simply ask:
"What does player Kiro own, and what are their production bonuses?"
"What is the current price of iron, and how deep is the order book?"
"Which countries is Freedonia at war with, and are there active battles?"
"Who is dealing the most damage in this battle?"
"Elencami gli ultimi 10 articoli pubblicati."
"Elencami gli articoli in italiano."
"Riassumi le ultime novità di WarEra tramite gli articoli."
The server fetches data and returns structured facts with stable identifiers, observation times
and explicit gaps. The assistant can combine those facts for analysis, calculations and simulations.
Successful tools return these facts in both structuredContent and a JSON text block in
content, after a short summary, so clients that consume only text receive the same data.
The output-byte limit applies to the projected facts before this compatibility copy is added.
For company construction, get_game_rules(topic="companies") includes the concrete
cost formula: configured increment × (owned companies + 1). With the current increment
of 50, the sixth company costs 300 concrete. This formula was verified against the
official companies page on 2026-10-06; the increment
comes from the fetched configuration. An explicit company number needs no player lookup.
For personalized questions such as production time for "my next company", the server
instructs the assistant to ask for the in-game username when no player identity is known.
Selected tools accept optional request-scoped WarEra credentials (api_key or jwt) in
player_context; the project never provides a default or global WarEra credential.
Related MCP server: warframe-mcp
Connect to the hosted MCP
Use this HTTPS MCP endpoint in Claude or ChatGPT:
https://warera-mcp-agkzl5m3va-ew.a.run.app/mcpRemote connections use Streamable HTTP and require no account or token.
Claude
Open Customize → Connectors → + Add → Add custom connector.
Enter WarEra as the name and the HTTPS endpoint above as the server URL.
Continue to the authentication settings and choose No sign in. Leave OAuth settings and request headers empty.
Click Add, then enable WarEra from + → Connectors in a conversation.
Try: "Using WarEra, what is the current market price of iron?"
The hosted endpoint requires no MCP client token. WarEra player API keys and JWTs are separate, optional credentials for selected tools; public tools need none. For Team or Enterprise, an organization owner or authorized administrator must add the connector before members can enable it. See Claude's remote connector guide.
ChatGPT
Use ChatGPT on the web. If required, enable Developer mode under Settings → Security and login. Workspace permissions may restrict access.
Open Plugins, select + → Create custom MCP server, and enter WarEra with the HTTPS
/mcpURL above.Select No authentication. Leave OAuth client ID and secret empty.
Review the connection warning, create the plugin, and install it.
Enable WarEra in a conversation and ask a game-data question.
See OpenAI's custom MCP setup guide.
Quick start
You need Python 3.11+ and uv.
git clone https://github.com/LorissDaniel/warera-mcp.git
cd warera-mcp
uv sync --locked
uv run warera-mcp # serves over stdioUse it from an MCP client (for example Claude Desktop) by adding it to the client's config:
{
"mcpServers": {
"warera": {
"command": "uv",
"args": ["--directory", "/path/to/warera-mcp", "run", "warera-mcp"]
}
}
}Run it as a small web service instead:
uv run warera-mcp --transport streamable-http --port 8000 # MCP endpoint: http://127.0.0.1:8000/mcpThis command binds to loopback by default. For remote use, configure client authentication, trusted hosts and HTTPS through your deployment or reverse proxy. The server warns about missing authentication/trusted hosts when configured to bind outside loopback; it cannot detect every externally reachable proxy configuration. See .env.example for the environment variable names. MCP client bearer tokens are separate from WarEra credentials.
If a desktop client cannot find uv, use its absolute executable path in command.
After updates, restart or reconnect the MCP server so the client refreshes its tool schemas.
Tools
Area | Tools |
Players |
|
Companies |
|
Discovery |
|
World |
|
Market |
|
Battles |
|
Mercenaries |
|
Rankings |
|
Labor |
|
Transactions |
|
Military units |
|
Events |
|
Articles |
|
Official configuration |
|
All 44 tools are marked read-only. There is deliberately no generic "call any endpoint" tool.
Locations and player resources
get_recommended_regions(item_code="iron", include_deposit=false) asks the game for
its ranked company locations excluding deposit bonuses. It exposes bonus components and
taxes as fractions, plus region/country names when available. API key is required;
JWT is never used for this operation, even when supplied. The ranking covers the recommendations
returned by the game (five in the verified responses), not every world region. offset and limit page
that returned list; deposit bonuses are never subtracted using an inferred formula.
get_player_resources(user_id=..., item_codes=["iron", "steel", "fish"]) reads available
money and basic materials from the player's inventory, market reservations, and owner-order
aggregates including quantities for sale. Use an exact username instead of user_id when
necessary. Set include_orders=false to skip the order read. Keep available materials,
market reservations and sell quantities separate: reservations and orders can describe
the same stock. Expected sales proceeds are not available money. Missing/malformed fields
remain unknown; a valid sparse quantity map treats omitted requested codes as zero.
Inventory and owner orders require JWT. On 2026-10-05, authorized live checks returned 401 anonymously, 403 with API key, and 200 with JWT for both reads. These responses are never shared-cached. The resource tool exposes only selected numeric fields and the requested player identity, without equipment, managers or other raw inventory fields.
Public operations always run anonymously, even if player_context contains credentials.
Credentials are requested only after a tool reports missing authentication. Authentication
is selected independently for each endpoint; there is no automatic retry with a JWT after
an API key is rejected. The project never loads credentials from another project's .env.
Multiple material prices
For price comparisons, use one call such as
get_market_prices(item_codes=["iron", "steel", "fish"]) instead of one
get_market_price call per material. Omit item_codes to retain the complete
catalog behavior. Lists accept 1–64 codes; duplicates are removed. Filtering is
local over one shared, cached itemTrading.getPrices snapshot; it does not issue
one upstream request per material. Prices remain sorted by descending value.
Omit limit to return every selected quote. If supplied, it applies after
filtering and sets truncated=true when prices are omitted. Missing/unquoted
codes are reported in missing_item_codes, while available prices are retained;
partial=true indicates missing quotes or truncation. Missing prices must not be
used as zero in calculations. These are global quoted prices; for visible
bids, asks and quantities, use search_market for each relevant material. Visible
orders are snapshots and do not guarantee execution or sufficient liquidity.
Filtered pages and visible market depth
get_work_market(item_code="iron", region_id=..., citizenship=..., level=18, energy=10, production=10) sends the documented offer filters upstream before
pagination. user_id filters by the offer's user ID. Zero numeric values are sent
explicitly; omitted values are not inferred from a player profile. The tool does
not independently certify eligibility. item_code selects the wage benchmark,
not the product of the offers. Wages retain API units; no hourly rate is inferred.
limit (1–10) controls the upstream offer page size. Continue with
page.next_cursor and the same filters. minimum_net_wage remains a local filter
of the fetched page, using gross wage when net wage is absent. A reported net wage
of zero remains zero. An empty filtered page can still have later matches when
page.has_more=true. Offer IDs, user/company/region IDs, remaining and initial
quantities, and timestamps support follow-up queries. If offers cannot be read,
partial=true and the absent page indicate unavailable coverage.
search_battles applies country_id, war_id, defender_region_id and
is_active upstream. A defender region is the attacked region. The optional
direction is forward or backward; these API pagination directions do not
promise chronological ordering. search_events applies country_id and
event_types upstream. Its parameter schema lists the documented event codes;
input casing is normalized and unsupported codes are rejected before a request.
Output event types are lowercase, with unknown: for unrecognized types.
If the API exceeds the requested page size, bounded output carries partial=true
and a warning about omitted rows; the cursor may not recover those rows.
For both tools, follow page.next_cursor with identical filters and direction
where applicable; a page is not complete historical coverage.
search_market(item_code="iron", max_orders=25) forwards max_orders as the API's
limit, supporting 1–100 visible orders per side. Existing buy orders are bids;
sell orders are asks. To estimate purchases choose side="sell"; to estimate
sale proceeds choose side="buy". With depth_quantity, compare returned
depth.quantity against the target: the reported VWAP may cover only a partial
fill. The book remains a bounded snapshot, not guaranteed executable liquidity.
get_player_companies requests up to 100 company IDs per upstream page using the
verified perPage parameter, then retrieves bounded detail batches using limit
and the configured fan-out cap. To consume the current page, follow next_offset
with the same cursor. Once next_offset is absent, follow page.next_cursor
with offset=0. total_count is returned only when the first upstream page
contains the entire owned list; a final continuation page's size is not a total.
Ownership lists can change between reads; preserve observation times.
Public player facts
get_player(user_id=...) returns the public profile's MU id, military rank,
active flag, creation date, numerical leveling/statistics and reported activity
timestamps, alongside skills and rankings. fields can select profile,
location, level, skills_summary, rankings_summary, activity and
statistics, missions and equipment; omitting fields selects all groups. The profile's military_unit_id
links directly to the MU tools without a membership search.
By default, get_player enriches user.getUserLite with reviewed game facts from
user.getUserById: region and location IDs, company and party references, profile
update time, reported MU maximum level rewarded, equipped-slot item IDs, mission
statistics/claim timestamps and completed-tour flags. The company_id reference
does not establish ownership; use get_player_companies for owned companies.
equipment_ids identifies equipped slots, not inventory quantities or full item
attributes. Missing fields remain unknown; account metadata and UI preferences
are not exposed. include_full_profile=false skips enrichment. Focused reads
containing only level, skills or rankings also use lite only. profile_source
reports lite or full; failed or mismatched full-profile reads retain lite facts
with partial=true and a warning. Additional maps are bounded to 64 entries.
skills and rankings remain compact numerical maps, compatible with older
scalar payloads. Nested skill summaries use reported total, falling back to
value only when total is absent; they do not recompute the game's formula.
skill_details additionally preserves level, current bar, base value, weapon,
equipment, overflow, limited amount, total, total after soft cap, regeneration
and prestige. Named percentage modifiers are exposed in modifiers_fraction
(e.g. militaryRankPercent:6.25 becomes militaryRank:0.0625). Skill totals/base
values keep the game's skill-specific units, including percentage-point values
where applicable. They must not be combined blindly with modifier fractions.
Future numeric skill components are kept in additional_numeric_components.
ranking_details preserves reported value, rank and tier independently.
wealth_breakdown preserves public stats.wealth components: money, items,
companies, equipments, weapons and total, plus additional numeric components
when reported. It belongs to the statistics field group and is capped at 64 entries.
Values and the reported total are retained independently; the server does not recompute
or reconcile them with the wealth ranking, which may reflect another snapshot.
The money component is not certified as spendable inventory money, and items
is an aggregate wealth component, not per-material quantities. Use get_player_resources
for available money and materials; that inventory read continues to require JWT.
Missing components remain unknown; reported zeros remain zero.
On 2026-10-05, closely spaced live MCP reads with its public cache disabled found
stats.wealth.money different from JWT inventory.money, while market.lockedMoney
was zero and the public value stayed unchanged before/after the inventory read.
This verifies that the two snapshots are not interchangeable; it does not establish
the statistic's formula or refresh interval. The server does not adjust the public
value into an inferred available balance. Direct requests with no-cache headers
and a unique URL still returned the same public number with Cloudflare reporting
DYNAMIC. This does not rule out game-side caching or stored statistics. The profile's
updated_at is not a wealth calculation timestamp; no age or meaning beyond the
reported component is inferred.
leveling, stats and activity map keys retain upstream field codes. Missing
facts are omitted, not replaced with zero. Map outputs are capped at 64 entries,
activity date lists at 20, and all results retain the existing byte budget.
Activity timestamps are public observations, not a guarantee of future activity.
No private inventory read or automatic company/MU/profile fan-out is triggered;
the LLM chooses which linked tools and field groups its analysis requires.
Military units
search_military_units(search="Husaru", member_id=..., owner_id=...) uses the
official MU API to search by text, membership or
ownership. All filters are optional; owner_id maps to upstream userId.
The default limit is 10 (maximum 20). Continue with page.next_cursor and the
same filters. The API has no documented country filter, so country-wide coverage
must not be inferred from a single page.
get_military_unit(military_unit_id=...) returns a compact dossier: identity,
owner, location, member/role counts, level, monthly damage, mercenary reputation,
active upgrade levels, manager/commander ids (up to 20 per role), last-announcement
time and the six reported ranking snapshots. roles_truncated flags capped role
lists; use the paginated roster with include_non_members=true for full coverage of
the identities returned by the API. Missing values remain unknown. Names are untrusted
player content. Wealth is a ranking value, not a verified inventory balance. Full member
lists, avatar URLs and per-user investment maps are excluded from the dossier; roster
and investment tools expose the analytical data in bounded pages.
get_military_unit_members(military_unit_id=..., offset=0, limit=10) pages the
public member roster with owner, manager and commander flags. Missing role data
remains unknown. Set include_non_members=true to include owner, managers and
commanders outside the roster. is_member distinguishes membership from a
management role, and total_count covers the selected set of identities.
Role flags reflect the API's roles.managers and roles.commanders lists. A listed
responsible user may belong to another MU, and a role reference may not match what
the game UI currently displays; the server does not independently verify effective
permissions. Use get_player(user_id=...) for individual profiles.
get_military_unit_investments(military_unit_id=..., offset=0, limit=10) pages
investedMoneyByUsers, including former members when reported. Amounts are
reported monetary investments, not treasury or upgrade resource balances. A
missing map returns available=false with unknown amounts/count; an explicitly
empty map returns available=true and zero entries. Pagination does not infer
investment history or fetch transaction records.
get_military_unit_upgrades reads headquarters and dormitories separately,
including disabled/pending status, investments and activation timestamps when
available. A failed upgrade read preserves the other result with partial=true.
The dossier's active levels do not include disabled upgrades.
get_military_unit_ranking(ranking_type="muWeeklyDamages", offset=0, limit=10)
also supports muDamages, muTerrain, muWealth, muBounty and muReputation.
Offsets page only the snapshot returned by WarEra; total_count is that snapshot's
size. Rosters and rankings may change between calls. Name lookups are limited to
five units and the configured fan-out budget. For a battle's MU contributions,
use get_battle_ranking(battle_id=..., entity_type="mu"), which now resolves
MU names with the same bounded, best-effort policy. The ranking tool now accepts
exactly one of battle_id, war_id or round_id, plus metric="damage",
"points" or "money". It forwards limit and cursor, returns page.next_cursor
and preserves the reported item_count. A legacy oversized response is capped
locally with a warning. A positive count with no rows is marked partial=true,
so it cannot be treated as zero participation. Battle dossiers/search results
include war_id, current round ids and the MU/country ids with orders on each
side. Round summaries/live snapshots preserve country ids, damage, points, hit
counts, tick counters/points and timestamps from the current nested API shape,
while accepting the older flat fields. Equipment and last-hit payloads remain
outside those compact summaries.
These reads were verified anonymously on 2026-10-05 against OpenAPI 0.17.4-beta
(machine-readable specification). They use
GET, public TTL caching and the existing output-byte limit. MU management actions
remain outside this read-only project. For MU transaction history use
search_transactions(military_unit_id=...) with a request-scoped API key.
Public identifier discovery
get_country_players(country_id=..., limit=10) returns player IDs and account
creation timestamps, with upstream cursor pagination. Follow page.next_cursor
with the same country. Account creation is not a country joining date or last
activity; one page is not total or active population. Use get_player for details.
search_entities(search="Loris") returns candidate IDs grouped by user, MU,
country, region, party and alliance. Offset/limit page the API's retained matches
locally per group; there is no upstream cursor or guarantee of complete search
coverage. Missing groups remain unknown; explicit empty lists are known empty.
It does not certify an exact identity. For an exact username use get_player.
Equipment, upgrades and government
get_player_equipment(user_id=...) or get_player_equipment(username="Loris")
returns publicly equipped item attributes, condition, skill bonuses and acquisition dates.
Explicit null slots appear in empty_slots; omitted slots are unknown. This is the
current loadout, not inventory or tradable stock. Slot maps are capped at 20 and skill
maps at 64 entries.
get_company_upgrades covers storage, automatedEngine and breakRoom;
get_region_upgrades covers bunker, base and pacificationCenter. Omit
upgrade_types for all three, or select a subset. Reported status/level,
money/concrete/steel investments and activation/change dates remain separate.
absent_upgrade_types means a successful null response; it does not infer a zero level.
unavailable_upgrade_types identifies failed or invalid reads and sets partial=true.
Use company/region tools for context and game configuration for supported upgrade costs/effects.
get_country_government(country_id=..., offset=0, limit=10) returns president/minister
user IDs, a locally paginated congress roster and reported activity dates. congress_member_count
covers the returned roster; a missing roster is unknown. Follow the user IDs with
get_player. These references describe reported roles, not independently verified permissions.
Rounds, orders, loot and mercenary contracts
get_round(round_id=...) retrieves a specific round, including battle/country links,
damage, points, hits, ticks and timestamps. get_round_hits pages the recent hit arrays
with separate snapshot_counts and has_more per side. Its offset/limit are local,
not historical API pagination. include_equipment=true adds weapon, ammo and up to
10 equipment items as recorded at the hit. A reported missed hit can still have
reported damage; neither is overwritten using an inferred formula.
get_battle_orders(battle_id=..., side="attacker") returns a locally paginated
order snapshot with country/MU/user links, priority and activity. The anonymous view
may hide text and rank. Empty text with rank zero is exposed as
text_and_rank_visibility="restricted_in_anonymous_view", with text/rank unknown.
It must not be interpreted as a public zero rank or permission to inspect private orders.
get_battle_loot(battle_id=..., user_id=...) preserves reported case counts,
hits, total damage, bounty/contract money and pool-loot numeric facts/references.
A missing summary produces an error, not zero earnings. Pool loot is capped at
20 entries; truncation sets partial=true. These are reported rewards, not a current balance.
search_mercenary_auctions(country_id=..., battle_id=..., status="won") applies
filters upstream. The schema lists supported status values; omitted status uses the
API default and does not promise all historical statuses. Follow page.next_cursor
with the same filters. Budget, minimum damage, current rates/payouts, winner IDs,
battle/round links and expiry remain distinct. include_bids=true adds up to
bid_limit bids per auction (maximum 20); bid_count covers the record and
bids_truncated signals omissions. Duration/rate fields retain API units; no
undocumented conversion or guaranteed final payout is inferred.
Global rankings
get_global_ranking(ranking_type="userDamages", offset=0, limit=10) supports all
36 documented user, country, alliance and MU ranking types. It preserves entity IDs,
reported rank/value/tier, tier thresholds and country/MU links when supplied.
There is no automatic profile fan-out; use linked tools as needed. Offsets page the
snapshot returned by the API, not the entire world population; snapshot_count
reports that snapshot's size. No historical week selector is documented. For MU name
expansion use get_military_unit_ranking. Wealth rankings are not spendable inventory.
Work details and API-key transactions
get_work_offer(work_offer_id=...) or get_work_offer(company_id=...) reads one
public offer; supply exactly one identifier. It includes wage/net wage, offer quantities,
minimum energy/production/level when supplied, linked entities and timestamps.
Use get_work_market for filtered offer discovery.
get_workers and search_transactions require player_context={"api_key":"..."}.
They were verified with API key on 2026-10-05; neither requires JWT and neither uses
shared caching. Credentials are never returned in the result.
get_workers(company_id=...) lists company workers; get_workers(user_id=...)
lists workers grouped across that user's employer company portfolio, not the user's
own employment. Supply exactly one scope. Wage, fidelity, joining/locking dates and
worker IDs support profile/company joins. Offset/limit page the returned snapshot
locally. snapshot_count and the separately reported reported_total_workers_count
are distinct observations; missing or failed counts remain unknown. Empty worker
arrays are known empty lists. Company summaries are capped at 20, with explicit truncation.
search_transactions(user_id=..., military_unit_id=..., transaction_types=["donation"]) also supports country, party and item-code filters. All filters apply upstream; omission leaves the API scope unfiltered. Follow page.next_cursor` with identical filters.
Transactions preserve reported money/quantity, timestamps, item attributes and separate
buyer/seller user, MU, country and party IDs. Keep those API labels: for a donation,
“buyer” is not automatically a goods buyer. Reported money is neither a unit price nor
a signed cash flow; establish the transaction semantics before calculating totals.
A page alone does not establish complete income, expenditure or historical coverage.
Articles
search_articles defaults to the latest published feed (feed="last", limit=10,
maximum 20). It forwards language codes (languages=["it"] for Italian), categories
(e.g. ["news"]), author_id and positive_score_only to WarEra. Other public feeds
are daily, weekly and top; use last for chronological news. Pass page.next_cursor
with the same filters to continue. Personal my/subscriptions feeds are not exposed.
Metadata-only results are compact. Set include_content=true for summaries: the feed
already includes article bodies, which the server converts from HTML into untrusted
plain text without fetching images or links. Each body is limited to 12,000 characters
(lower it with content_max_chars, minimum 280); content_truncated and warnings
identify incomplete text. The existing output-byte budget still applies: request fewer
articles or shorter content if necessary. The LLM writes the summary, cites titles/IDs,
authors and publication dates, and distinguishes player claims from official announcements.
get_article(article_id=...) returns only title and basic statistics via the lite
endpoint. It does not provide body text. The full-detail article.getArticleById endpoint
is deliberately excluded because it can count a view; summaries use the paginated feed.
Both exposed queries were checked anonymously against the
official API documentation.
How it works (the short version)
Read-only by design. The client calls only explicitly reviewed read operations. Most are public; selected reads require request-scoped authentication. State-changing operations and the potentially view-counting full article endpoint are excluded.
Structured, linkable facts. Tools project upstream data into documented fields; some combine related reads. The assistant chooses further tools using stable IDs or item codes and retains snapshot times, units and coverage limits.
Bounded. Results, number of upstream calls, response size and time per request are all capped, so one question can't run away.
Stateless and lightweight. No database and no accounts. Only a small in-memory cache of public data.
Game text is treated as untrusted. Player and company names are cleaned and length-limited before the assistant sees them.
Privacy & security
Public operations run anonymously and never forward supplied credentials.
Region recommendations, workers and transactions require API key.
Inventory and owner orders require JWT; current equipped items are public.
Configuration tools always read anonymously and do not accept
player_context.If supplied,
player_contextcarries the caller's own request-scopedapi_keyorjwt.The project has no default or global WarEra credential.
Submitted credentials are not logged, cached or persisted by the server, but they are sent in the MCP tool request and may be visible in the LLM/client conversation history.
The server has no persistent conversation store. Public responses can be held in its in-memory TTL cache, and operational logs record sanitized request metadata. The MCP client, hosting platform and reverse proxy have their own storage/logging policies.
Found a security problem? Please report it privately (for example via your hosting platform's security-advisory feature) rather than opening a public issue.
Configuration
Settings are read from WARERA_MCP_* environment variables. .env.example documents
commonly used settings; the complete list and defaults are in
src/warera_mcp/config.py. The server does not automatically
load a .env file, so pass these variables through your shell, MCP client configuration,
or deployment environment. Command-line options can override the bind host, port and log level.
The upstream defaults to https://api2.warera.io and rejects another host unless
WARERA_MCP_ALLOW_CUSTOM_UPSTREAM=true is explicitly enabled for local mocks. HTTP
redirects are never followed.
The upstream response cap defaults to 8,000,000 bytes to accommodate verified global ranking snapshots larger than 2 MB. The complete HTTP body (including a batch) is still bounded. Structured tool output remains capped at 262,144 bytes; use bounded pages and optional detail flags to control output size.
Game rules, skill progression, item details and schedule data are fetched from WarEra's
gameConfig.getGameConfig and gameConfig.getDates queries. When public caching is
enabled, their cache lifetimes are five minutes and 30 seconds respectively. Set
WARERA_MCP_CACHE_ENABLED=false to disable caching; API batching works independently.
Results include the time the server fetched the data and a SHA-256 fingerprint computed
locally from the returned content. The fingerprint is not an official game revision.
These tools expose selected fields from the API responses, including production recipes,
skill levels, upgrade costs and schedule timestamps. They do not provide every game
formula. get_item_catalog returns a separate built-in list of item codes; configuration
items and the live market price list can differ from that list. Player skill summaries
are included only when the public profile supplies them.
Company overviews fetch recipes from game configuration when available. Raw materials expose
production points per unit through get_item_details, have no ingredient recipe, and do not trigger
missing-recipe warnings. Manufactured products still require validated recipe inputs.
Python integrations can supply a recipe catalog through ServiceRuntime to override that lookup;
the standard CLI uses no local recipe overrides. Contract fixtures are used only by tests and are not
production defaults.
API batching
Concurrent upstream reads with identical authentication headers are collected for
up to 300 ms and sent directly to WarEra in a single GET tRPC batch. Identical
reads within that batch share one response; responses are not retained by the
batcher. This works with WARERA_MCP_CACHE_ENABLED=false.
Company details and bonuses, battle details and live status, and player profile enrichment can share batches. Reads that depend on an earlier result still run in separate stages. Sequential MCP tool invocations cannot share a batch.
Batches send early at 20 pending calls and split before their encoded URL exceeds 8000 bytes. Isolated reads use the original single-query GET format. The existing response byte limit applies to the entire batch. Queue capacity bounds active and pending logical reads; cancellation removes unused work without affecting other callers. Each item retains its own result, error, and retry budget.
Configure batching through:
Environment variable | Default | Meaning |
|
| Set |
|
| Collection delay per stage (0–0.4 seconds) |
|
| Maximum pending calls per batch (1–50) |
|
| Maximum encoded batch URL size |
An individual query too large for the batch URL budget uses the existing single
GET path. Transport limits and rate limiting apply to physical HTTP requests.
With batching enabled, circuit health is also recorded once per HTTP attempt;
retries check the circuit before sending again. warera_requests_total counts
logical reads, while warera_http_requests_total counts actual HTTP attempts;
warera_batches_total and warera_batch_size describe multi-query batches.
Batching reduces HTTP overhead; WarEra may still count each procedure toward its
API quota.
Development
uv sync --locked
uv run pytest # tests run offline against a stubbed API
uv run ruff check . # lint
uv run mypy # strict type checkingThe test suite never calls the real game API unless you opt in with WARERA_MCP_LIVE_TESTS=1.
Contributing
Issues and pull requests are welcome. Please keep changes small and focused, add or update tests,
and make sure ruff, mypy and pytest pass. The one hard rule: this project stays read-only —
changes that add anything able to modify game state will not be accepted.
Acknowledgements
Built with the help of AI tooling, by a player, for players. Thanks to the WarEra community for sharing what they've learned about the game.
License
Released under the MIT License. Provided "as is", without warranty of any kind.
Available Tools
13 toolsget_battleARead-onlyIdempotent
Get a battle's status: sides, current round and optionally a live snapshot. Live values are volatile snapshots with an explicit tick timestamp. It does not return last-hits lists or equipment payloads.
| Name | Required | Description | Default |
|---|---|---|---|
| battle_id | Yes | Opaque WarEra identifier. | |
| player_context | No | Optional per-request WarEra credentials: an object containing api_key or jwt. Never use a project-wide or default credential. | |
| include_history | No | Include previous rounds when available. | |
| include_live_status | No | Also fetch the live round snapshot. |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations already declare readOnly/idempotent/non-destructive, so the bar is lower, and the description still adds real value: live values are volatile snapshots stamped with an explicit tick timestamp, plus an explicit statement of what is not returned. It stops short of describing pagination or history behavior for the include_history path.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Two tight sentences with the core purpose front-loaded and the volatility caveat and exclusions packed into the second. Every clause earns its place.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
With no output schema, the description carries the burden of telling the agent what comes back, and it does: sides, current round, optional live snapshot, plus explicit exclusions. The picture is nearly complete, with only the history-rounds behavior left unstated.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema description coverage is 100%, so the four parameters are already fully documented, and the description adds almost nothing beyond implying the live snapshot is optional via include_live_status. The include_history parameter, which also changes what rounds are returned, is never mentioned in the description. Baseline 3 is appropriate.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
States a specific verb and resource ('Get a battle's status') and enumerates the returned content (sides, current round, optional live snapshot). It reads as distinct from search_battles or get_battle_ranking, though it never explicitly contrasts itself with those siblings.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
Usage is implied by the tool name and the returned fields, but there is no explicit when-to-use guidance or routing to siblings like search_battles or get_battle_ranking. The negative scope note (no last-hits lists or equipment payloads) does help an agent rule this tool in or out, which lifts it above pure inference.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
get_battle_rankingARead-onlyIdempotent
Get a battle leaderboard by damage or points for players, countries, or military units on one side. The upstream ranking is unbounded, so results are capped locally and truncated says whether more rows exist. This is a battle ranking, not the deferred global wealth ranking.
| Name | Required | Description | Default |
|---|---|---|---|
| side | No | Which side of the battle to rank. | merged |
| limit | No | Maximum rows to return (1-10). | |
| metric | No | Ranking metric. | damage |
| battle_id | Yes | Opaque WarEra identifier. | |
| entity_type | No | Which entity type the ranking lists. | user |
| player_context | No | Optional per-request WarEra credentials: an object containing api_key or jwt. Never use a project-wide or default credential. |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations already cover read-only/idempotent safety, but the description adds real behavioral context: the upstream ranking is unbounded, results are capped locally, and the `truncated` field signals whether more rows exist. That truncation contract is exactly what an agent needs and is not derivable from annotations or schema.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Three short sentences, front-loaded with the core purpose, then the truncation caveat, then the disambiguation. No filler, though the final disambiguation sentence references a tool not present in the sibling list, slightly diluting its payoff.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
With no output schema, the description usefully names the `truncated` return field and the local cap, and it covers the ranking axes. It omits return row shape and credential/player_context handling, so it is strong but not fully complete for a 6-param tool.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema description coverage is 100% and enums document side/metric/entity_type, so the schema does the heavy lifting. The description loosely restates the metric and entity-type options ("damage or points for players, countries, or military units") but adds no format or syntax beyond the schema; baseline 3 applies.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
States a specific verb+resource (get a battle leaderboard) plus the ranking dimensions (damage/points; players/countries/military units) and explicitly separates itself from the global wealth ranking. An agent can pick it against the sibling get_battle/search_battles without reading the schema.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
Gives clear context for the call (battle ranking) and rules out a plausible look-alike (the deferred global wealth ranking). It does not state when to prefer it over siblings like get_battle or search_battles, so it stops short of full when/when-not guidance.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
get_company_overviewARead-onlyIdempotent
Get one company's details: what it produces, where it sits, its workforce and its production bonus (normalized to a fraction). Recipe inputs are only reported when a validated local catalog is available, and they describe configured requirements, not current stock.
| Name | Required | Description | Default |
|---|---|---|---|
| company_id | Yes | Opaque WarEra identifier. | |
| player_context | No | Optional per-request WarEra credentials: an object containing api_key or jwt. Never use a project-wide or default credential. | |
| include_region_context | No | Also resolve the company's region. |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations already declare readOnly/idempotent/non-destructive, but the description adds genuinely non-obvious behavior: recipe inputs appear only when a validated local catalog exists, and they reflect configured requirements rather than current stock. That kind of conditional-availability disclosure is not derivable from the schema. It stops short of covering error handling or credential behavior.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Two sentences, front-loaded with the core purpose before the caveat, with no filler. The second sentence is dense but each clause carries real information about return behavior.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
There is no output schema, so the description carries the burden of describing return contents, and it does so: the four detail categories plus the conditional recipe-input caveat. Combined with 100% schema coverage for inputs, an agent has everything needed to call it correctly.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema description coverage is 100%, so all three parameters are already documented in the schema, which sets the baseline at 3. The description adds only indirect signal ('where it sits' hinting at region context, 'normalized to a fraction' clarifying the bonus format) rather than parameter-level guidance.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description states a specific verb and resource ('Get one company's details') and enumerates the actual payload (production, location, workforce, production bonus). It is clear what the tool returns, though it never names or contrasts itself with the plausible sibling get_player_companies, so the agent must infer the boundary.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
Usage is implied by 'one company's details' versus the list-style siblings, but there is no explicit 'use this when' statement, no mention of when to prefer get_player_companies or region/country tools, and no prerequisites or exclusions. Adequate but with a clear gap.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
get_country_overviewARead-onlyIdempotent
Get selected verified facts about a country plus, optionally, its regions. Names are matched exactly and case-insensitively, and this is a current snapshot only. It does not report war relationships — use get_country_wars for those.
| Name | Required | Description | Default |
|---|---|---|---|
| country_id | No | Opaque WarEra identifier. Prefer this over a name when you have it. | |
| country_name | No | Exact country name. | |
| limit_regions | No | Maximum regions to list (1-20). | |
| player_context | No | Optional per-request WarEra credentials: an object containing api_key or jwt. Never use a project-wide or default credential. | |
| include_regions | No | Also list the country's regions. |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations already declare readOnly, idempotent, non-destructive, open-world behavior, so the safety profile is covered. The description adds meaningful non-annotation context: name matching is exact and case-insensitive, and the result is 'a current snapshot only' (no history). It does not describe pagination or response shape, but for a read-only tool this is solid added value.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Two sentences, zero filler, front-loaded with the core action and scope, followed by the matching rule and the sibling exclusion. Every clause carries information an agent needs.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
For a read-only, 5-parameter tool with full schema coverage and rich annotations, the description supplies the missing behavioral pieces (exact case-insensitive matching, snapshot-only, war exclusion). It does not enumerate what facts are returned, but with no output schema and a well-annotated read operation, this is nearly complete.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema description coverage is 100%, so the baseline is 3. The description adds semantics beyond the schema by specifying that names are matched exactly and case-insensitively, which clarifies the country_name parameter's matching behavior, and reinforces that regions are optional (include_regions). That justifies a bump above baseline.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
States a specific verb (get) and resource (country overview), and explicitly scopes it to 'selected verified facts about a country plus, optionally, its regions.' It names the sibling it excludes (get_country_wars), so an agent can differentiate. The only weakness is that 'selected verified facts' leaves the actual content of the payload undefined.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
Gives an explicit exclusion and alternative: 'It does not report war relationships — use get_country_wars for those.' That is real routing guidance. However, it offers no guidance on when to prefer this over other siblings like get_region or get_company_overview, so it stops short of full when/when-not coverage.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
get_country_warsARead-onlyIdempotent
Show the countries this country is currently listed as at war with, plus its active battles. This is a current snapshot from the country's war relationship field, not a war-history or treaty report; an empty result is not proof that no battles ever occurred.
| Name | Required | Description | Default |
|---|---|---|---|
| country_id | No | Opaque WarEra identifier. Prefer this over a name when you have it. | |
| country_name | No | Exact country name. | |
| limit_battles | No | Maximum active battles (1-10). | |
| player_context | No | Optional per-request WarEra credentials: an object containing api_key or jwt. Never use a project-wide or default credential. | |
| include_active_battles | No | Also fetch active battles involving the country. |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations already cover read-only, idempotent, open-world safety, so the bar is lower. The description adds genuinely useful behavioral context: the data source (war relationship field), snapshot-in-time semantics, and the interpretation trap of empty results. Return format and pagination are not described, but no output schema exists to cover that.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Two sentences, no filler, with the primary capability front-loaded and the important caveat placed last. Every clause carries information.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
For a five-parameter, zero-required read tool with no output schema, the description conveys what comes back (war list plus active battles) and the limits of that data. It does not explain how country_id vs country_name are resolved or the default/limit behavior, though the schema covers those.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema description coverage is 100%, so the schema already documents country_id, country_name, limit_battles, player_context, and include_active_battles with constraints. The description only indirectly hints at the battle-listing behavior and adds no syntax or format detail beyond the schema, so the baseline 3 applies.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
States a specific verb ('Show') and two concrete resources (war relationships and active battles) scoped to a single country. It is clearly distinguishable from siblings like search_battles and get_battle, which operate on battles rather than a country's war list.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
Explicitly frames when the tool applies ('current snapshot from the country's war relationship field') and when it does not ('not a war-history or treaty report'), plus a caveat that an empty result is not proof of no historical battles. It does not, however, name an alternative sibling for historical war data.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
get_market_priceARead-onlyIdempotent
Get the latest global quoted price for one item. This is a single price snapshot for one item, not an order book or a market average.
| Name | Required | Description | Default |
|---|---|---|---|
| item_code | Yes | WarEra item code, e.g. 'iron' or 'bread'. | |
| player_context | No | Optional per-request WarEra credentials: an object containing api_key or jwt. Never use a project-wide or default credential. |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations already declare readOnlyHint, idempotentHint, openWorldHint, and destructiveHint=false, so the safety profile is fully covered. The description adds the meaningful behavioral fact that the result is a global quote rather than an order book or average, but says nothing about freshness/latency, rate limits, or credential behavior.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Two tight sentences with zero waste; the core scope statement is front-loaded and the disambiguation follows. Every sentence earns its place.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
For a simple two-parameter read tool with full annotation coverage and no output schema, the description tells the agent what the returned value represents (a latest global quoted price for one item). It stops short of describing freshness or handling of unknown item codes, but nothing critical to invoking it is missing.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema description coverage is 100%: item_code is documented with examples ('iron', 'bread') and player_context explains the credential shape, so the schema does the heavy lifting. The description only implies the single-item constraint ('for one item') and adds no syntax or format detail beyond the schema, warranting the baseline 3.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
States a specific verb and resource ('Get the latest global quoted price') and immediately bounds the scope ('single price snapshot for one item'). An agent can distinguish this from the sibling search_market, which suggests a broader search/list operation.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
The description clarifies what the tool is not (not an order book, not a market average), which implies usage boundaries, but it never names an alternative tool or states the condition under which it should be chosen over search_market or search_events. Usage is inferable rather than explicit.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
get_playerARead-onlyIdempotent
Get a player's public profile and selected public stats. Use the WarEra user ID when available; username resolution requires an exact, unambiguous match and otherwise asks you to disambiguate. Does not return private inventory, balance, or session-only data.
| Name | Required | Description | Default |
|---|---|---|---|
| fields | No | Field groups to include; omit for all. | |
| user_id | No | Opaque WarEra identifier. Prefer this over a name when you have it. | |
| username | No | Exact in-game username. | |
| player_context | No | Optional per-request WarEra credentials: an object containing api_key or jwt. Never use a project-wide or default credential. |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations already declare readOnlyHint, idempotentHint, destructiveHint=false and openWorldHint, so the safety profile is covered. The description adds genuinely new behavioral context: the ambiguity-resolution behavior for usernames and the explicit exclusion of private inventory, balance, and session-only data, which tells the agent what it will not get back.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Three sentences, zero waste, and the core purpose is front-loaded ahead of the identifier guidance and the exclusion note. Each sentence carries distinct information (what it returns, how to identify the player, what is omitted).
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
With no output schema, the description correctly states the return scope and its exclusions, and annotations cover safety. Minor gaps remain: it does not say what happens when no identifier is supplied despite zero required parameters, and the fields projection is left entirely to the schema.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema description coverage is 100%, so every parameter is already documented, including the 'prefer this over a name' note on user_id that the description largely repeats. The only semantic addition is the disambiguation behavior for username, which is behavioral rather than parameter-level, so the baseline 3 holds.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description gives a specific verb and resource ('Get a player's public profile and selected public stats') and scopes it with a negative statement about private inventory, balance, and session-only data. It does not name any sibling tool explicitly, so an agent must infer the boundary against get_player_companies on its own, which keeps it just short of a 5.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
It gives clear operative guidance: prefer the WarEra user ID when available, and expect username resolution to require an exact, unambiguous match with a disambiguation follow-up otherwise. It stops short of stating when to reach for this tool versus search_events or the overview tools, so there is no explicit alternative routing.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
get_player_companiesARead-onlyIdempotent
List the companies a player owns, with product, location, workforce and optional production bonus. This answers ownership questions in one call instead of many company lookups. It is not a country-wide company directory.
| Name | Required | Description | Default |
|---|---|---|---|
| limit | No | Maximum companies to return (1-10). | |
| offset | No | Local offset into the owned list. | |
| user_id | No | WarEra user id (preferred). | |
| username | No | Exact in-game username. | |
| include_bonus | No | Fetch each company's production bonus. | |
| player_context | No | Optional per-request WarEra credentials: an object containing api_key or jwt. Never use a project-wide or default credential. |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations already declare readOnlyHint=true, idempotentHint=true, destructiveHint=false, so the safety profile is covered. The description adds the aggregation benefit and that bonus fetching is optional, but says nothing about pagination behavior, result ordering, or what happens when the user is not found.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Three short sentences, no filler, with the core purpose front-loaded and the scope exclusion last. Every sentence carries information.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
With no output schema, the description usefully names the returned fields and the optional bonus, and the player_context parameter documents the per-request credential requirement. Minor gap: no mention of paging semantics or result ordering, though the schema covers limit/offset bounds.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema description coverage is 100%, so limit/offset/user_id/username/include_bonus/player_context are all documented in the schema. The description only echoes the optional production bonus, adding no format or precedence guidance (e.g., user_id vs username) beyond what the schema states. Baseline 3 is appropriate.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
States a specific verb and resource ('List the companies a player owns') and enumerates the returned fields (product, location, workforce, production bonus). The negative clause 'not a country-wide company directory' separates it from directory-style lookups such as get_country_overview.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
Gives a clear usage trigger ('answers ownership questions in one call instead of many company lookups') and a when-not condition ('not a country-wide company directory'). It never names the specific sibling to use instead, so routing is implied rather than explicit.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
get_regionARead-onlyIdempotent
Get a region's detail by id or exact name: population, development, climate, deposit and optionally its country. Region names repeat across countries, so ambiguous matches are rejected and reported instead of guessed. It does not recommend where to build.
| Name | Required | Description | Default |
|---|---|---|---|
| region_id | No | Opaque WarEra identifier. Prefer this over a name when you have it. | |
| region_name | No | Exact region name. | |
| player_context | No | Optional per-request WarEra credentials: an object containing api_key or jwt. Never use a project-wide or default credential. | |
| include_country | No | Also resolve the linked country. |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations already declare readOnly, idempotent, openWorld and non-destructive, so the safety profile is covered. The description adds genuinely new behavior: ambiguous name matches are rejected and reported rather than guessed, which is important error semantics an agent must anticipate.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Three sentences, zero filler, with the primary capability front-loaded and the ambiguity caveat immediately after. Every sentence carries information the agent needs.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
With no output schema, the description compensates by naming the returned fields, and the ambiguity and no-recommendation caveats cover the main failure modes. It does not say what the ambiguity-rejection response looks like or what 'deposit' contains, minor gaps for a single-entity read.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema description coverage is 100%, so all four parameters are already documented, including the preference for region_id. The description reinforces id-or-exact-name and the optional country resolution but adds no syntax or format detail beyond the schema, making 3 the correct baseline.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
States a specific verb (Get) and resource (region) and enumerates the returned fields: population, development, climate, deposit, and optionally country. No sibling tool in the list touches regions, so the scope is unambiguous without further differentiation.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
Tells the agent it can look up by id or exact name and explains the ambiguity handling that governs name lookups. It also states a when-not ("does not recommend where to build"), though it names no alternative tool for that need, leaving the agent to infer the right sibling.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
get_work_marketARead-onlyIdempotent
Get the wage benchmark for one item together with a small set of matching work offers. Offers are filtered locally on the first upstream page. It reports wage facts only and does not assess eligibility or suitability.
| Name | Required | Description | Default |
|---|---|---|---|
| limit | No | Maximum work offers to return (1-10). | |
| item_code | Yes | WarEra item code, e.g. 'iron' or 'bread'. | |
| region_id | No | Filter offers by region id. | |
| player_context | No | Optional per-request WarEra credentials: an object containing api_key or jwt. Never use a project-wide or default credential. | |
| minimum_net_wage | No | Minimum acceptable wage. |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations already cover the safety profile (readOnly, idempotent, non-destructive). The description adds genuinely useful behavior beyond that: offers are filtered locally on the first upstream page, meaning results are a bounded subset rather than an exhaustive market scan. It also draws a clear scope line at wage facts only. It does not mention rate limits or return shape, keeping it short of a 5.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Three short sentences, front-loaded with the core capability and followed by the two constraints an agent most needs. Every sentence carries distinct information with no repetition of the schema.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
For a five-parameter, read-only tool with no output schema, the description conveys the primary return (wage benchmark plus offers) and the important caveat that offer filtering is local to one upstream page. It could say more about what the wage benchmark contains or how the offer set is ordered, but nothing essential to a correct call is missing.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema description coverage is 100%, so limit, item_code, region_id, player_context and minimum_net_wage are all documented in the schema itself. The description adds only the loose notion of 'one item' and 'matching offers', which does not extend parameter meaning. Baseline 3 applies.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
States a specific verb and resource ('get the wage benchmark for one item') plus the accompanying payload (matching work offers). This clearly separates it from price-oriented siblings like get_market_price and search_market, though it never names an alternative explicitly.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
The description implies usage through scope boundaries ('reports wage facts only and does not assess eligibility or suitability'), which tells the agent what this tool is not for. However, it gives no explicit when-to-use condition or pointer to a sibling when the agent wants prices or eligibility rather than wages.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
search_battlesARead-onlyIdempotent
List battles, optionally filtered by country and active state. Each side includes the human-readable country name and id. Without a filter this is the first upstream page, and its ordering is not guaranteed, so do not describe it as 'latest'. For a battle leaderboard use get_battle_ranking.
| Name | Required | Description | Default |
|---|---|---|---|
| limit | No | Maximum rows to return (1-10). | |
| cursor | No | Cursor from a previous page's `next_cursor`. Treat it as opaque. | |
| is_active | No | Filter to active or finished battles. | |
| country_id | No | Filter by country id. | |
| player_context | No | Optional per-request WarEra credentials: an object containing api_key or jwt. Never use a project-wide or default credential. |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations already declare readOnlyHint, idempotentHint, destructiveHint=false, and openWorldHint, so safety is covered. The description adds behavior the annotations cannot: unfiltered requests return the first upstream page with no guaranteed ordering, and each side carries a human-readable country name plus id. It does not cover rate limits or page-size behavior, keeping it short of a 5.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Three short sentences, front-loaded with the core purpose, then the ordering caveat, then the sibling routing hint. Every sentence earns its place with no filler.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
Without an output schema, the description usefully discloses that each side includes a country name and id, and it warns about pagination/ordering. It is nearly complete for a read-only list tool, though it does not explain the meaning of a 'side' or how cursor iteration terminates.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema description coverage is 100%, so the limit, cursor, is_active, and country_id parameters are fully documented in the schema itself. The description adds no parameter syntax or format detail beyond what the schema already provides, so the baseline 3 applies.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
States a specific verb and resource ('List battles') plus the two filters that define its scope (country, active state). It explicitly differentiates itself from the sibling get_battle_ranking, so an agent can route correctly without opening either schema.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
Gives both a when-to-use condition ('optionally filtered by country and active state') and an explicit alternative ('For a battle leaderboard use get_battle_ranking'). It also states an operational caveat — unfiltered results are the first upstream page with non-guaranteed ordering — that guides how the caller should present results.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
search_eventsARead-onlyIdempotent
Retrieve a bounded page of recent world events, optionally filtered by country or event type. Filters are applied locally to one fetched page, so a filtered page may look sparse while more events remain upstream. It does not provide a complete event history, and event summaries are untrusted third-party text.
| Name | Required | Description | Default |
|---|---|---|---|
| limit | No | Maximum rows to return (1-20). | |
| cursor | No | Cursor from a previous page's `next_cursor`. Treat it as opaque. | |
| country_id | No | Keep events related to this country. | |
| event_types | No | Keep only these event types (case-insensitive, at most 10). | |
| player_context | No | Optional per-request WarEra credentials: an object containing api_key or jwt. Never use a project-wide or default credential. |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Goes well beyond the annotations (which only cover read-only/idempotent safety): it discloses the local-filter-on-one-page behavior, the resulting sparse-page failure mode, the incompleteness of history, and that event summaries are untrusted third-party text. These are non-obvious behavioral traits an agent must know.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Three sentences, front-loaded with the core purpose followed by the two most important caveats (local filtering, untrusted text). No filler.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
Annotations cover the safety profile and the schema covers all parameters, so remaining burden is behavioral. The description addresses pagination filtering quirks, history limits, and untrusted content well; cursor semantics are left to the schema, which is acceptable since there is no output schema.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema description coverage is 100%, so the schema already documents limit, cursor, country_id, event_types, and player_context. The description adds no parameter-level detail beyond what the schema provides, so the baseline of 3 applies.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
States a specific verb and resource ('Retrieve a bounded page of recent world events') and names the two filter axes (country, event type). It is clearly distinguishable from siblings like search_battles or get_country_wars, which cover different domains.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
The description makes clear this is for recent, bounded, page-based event retrieval rather than complete history, and warns that filtering happens post-fetch. It does not name an alternative sibling for fuller event coverage, but the scope constraint effectively tells the agent when this tool is and isn't appropriate.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
search_marketARead-onlyIdempotent
Inspect the visible buy/sell order book for one item, optionally estimating depth for one side. These are the top visible orders only: not guaranteed liquidity and never a full-market average. Order owners are deliberately omitted.
| Name | Required | Description | Default |
|---|---|---|---|
| side | No | Book side to return. | both |
| item_code | Yes | WarEra item code, e.g. 'iron' or 'bread'. | |
| max_orders | No | Maximum price levels per side (1-10). | |
| depth_quantity | No | Estimate visible depth for this quantity on a single side. | |
| player_context | No | Optional per-request WarEra credentials: an object containing api_key or jwt. Never use a project-wide or default credential. |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations already declare readOnly/idempotent/non-destructive/openWorld, so the bar is lower, and the description adds real value: it discloses that only top visible orders are returned, that this is not guaranteed liquidity or a full-market average, and that order owners are omitted. It does not cover rate limits or credential scoping beyond what the schema says.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Three tight sentences, front-loaded with the core action, then immediately the critical data limitations. No filler; every clause carries information an agent needs.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
For a read-only inspection tool with no output schema, the description covers what the data represents and its limitations well. Missing only explicit routing guidance to sibling price tools, which would round it out.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema description coverage is 100%, so baseline is 3. The description adds marginal meaning ('for one item', 'estimating depth for one side') that reinforces the item_code and depth_quantity semantics, but the schema already documents each parameter including the single-side depth constraint.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
States a specific verb ('Inspect') and resource ('visible buy/sell order book for one item'), with the depth-estimation capability noted. It is distinguishable from siblings like get_market_price and get_work_market by the 'order book' framing, though it never names or contrasts those siblings explicitly.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
The description implies a read-only market-inspection use case but gives no explicit when-to-use/when-not-to-use guidance or alternative tools (e.g., get_market_price for a single price). The caveats about data scope hint at the intended usage context without stating it.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
Tool Schema Changelog
Recent tool additions, removals, and schema changes observed during successful MCP inspections.
13 tool updates
v0.1.0- First observed
get_battle - First observed
get_battle_ranking - First observed
get_company_overview - First observed
get_country_overview - First observed
get_country_wars - First observed
get_market_price - First observed
get_player - First observed
get_player_companies - First observed
get_region - First observed
get_work_market - First observed
search_battles - First observed
search_events - First observed
search_market
TDQS
Scored across 13 tools
Each tool targets a distinct resource and action: player, company, country, region, market, work market, battles, battle detail, and battle ranking. Overlaps such as country wars versus battle search are explicitly clarified, and no two tools appear to do the same thing.
Most names follow predictable get_* for retrievals and search_* for list/search operations. A few list-like tools use get_ (e.g., get_player_companies, get_country_wars), which is a minor deviation but still readable.
Thirteen tools are well within a reasonable range and each covers a meaningful slice of the WarEra data domain. The set does not feel bloated or artificially thin.
The read-only surface covers core entities and workflows: players, companies, countries, regions, markets, work, wars, battles, and rankings. Minor gaps exist, such as no write/action tools and no global wealth ranking, but these appear intentional or clearly bounded.
Maintenance
Related MCP Connectors
Read-only search of 2,189 AI agent tools (MCP servers, x402 APIs) with daily automated trust scores.
Web search, browser automation, scraping, crawling and CAPTCHA solving for AI agents.
Discover, inspect and run 63,000+ agent tools from one balance. Pay per call, no subscriptions.
Public web tools for agents: product extraction, claim checks, webpage QA and ranked audits.
Related MCP Servers
- AlicenseNot gradedqualityCmaintenanceProvides AI assistants with access to real-time Brawl Stars game data including player statistics, club information, brawler details, battle logs, and current events through the Brawl Stars API.17 npm1MIT
- AlicenseAqualityDmaintenanceProvides AI assistants with real-time access to Warframe game data including world state, item stats, market prices, drop tables, builds, crafting, and farming optimization through 19 tools.1936 npm1MIT
- FlicenseAqualityDmaintenanceEnables AI assistants to look up World of Warcraft character information and reputation from Blizzard's Armory website.21-
- AlicenseAqualityBmaintenanceEnables AI agents to search EVE Online items, validate ship fits against fitting limits, compute combat stats like DPS and EHP, and retrieve Jita market prices.4MIT