koala73/worldmonitor · error · Error

get_intel_timeline requires at least one of domain ("conflic

Error message

get_intel_timeline requires at least one of domain ("conflict", "military", or "energy") or country (ISO 3166-1 alpha-2) — those are the two indexed scopes on the history store.

What it means

Thrown by the get_intel_timeline MCP tool as a client-side pre-flight validation before the server-side handler is even called. The tool requires at least one indexed scope — either a domain ('conflict', 'military', or 'energy') or a country (ISO 3166-1 alpha-2) — because those are the only two indexes on the history store. Without one, the handler would return a 400; this check turns that opaque failure into an actionable message and saves the round-trip. The handler remains the enforcing authority.

Source

Thrown at api/mcp/registry/rpc-tools.ts:1861

    },
    outputSchema: {
      type: 'object',
      required: ['records', 'partial', 'upstreamUnavailable'],
      properties: {
        records: { type: 'array', description: 'Scoped history, newest first.', items: INTEL_HISTORY_RECORD_SCHEMA },
        partial: { type: 'boolean', description: 'True when the bounded post-filter window may omit older matching events.' },
        upstreamUnavailable: { type: 'boolean', description: 'True when the history store could not be reached. `records` is then empty because the read failed — never read that as "nothing happened in this window".' },
      },
    },
    annotations: { readOnlyHint: true, destructiveHint: false, idempotentHint: true, openWorldHint: false },
    _execute: async (params, base, context, execution) => {
      // Scope is mandatory server-side (a 400 from the handler). Checking it
      // here turns an opaque downstream failure into an actionable message and
      // saves the round-trip; the handler stays the enforcing authority.
      const domain = typeof params.domain === 'string' ? params.domain.trim() : '';
      const country = typeof params.country === 'string' ? params.country.trim() : '';
      if (!domain && !country) {
        throw new Error('get_intel_timeline requires at least one of domain ("conflict", "military", or "energy") or country (ISO 3166-1 alpha-2) — those are the two indexed scopes on the history store.');
      }

      const query = new URLSearchParams();
      addStringParam(query, 'domain', domain);
      addStringParam(query, 'country', country);
      addIntelHistoryNumber(query, 'from', params.from);
      addIntelHistoryNumber(query, 'to', params.to);
      addIntelHistoryNumber(query, 'limit', Math.min(Number(params.limit ?? MCP_HISTORY_TIMELINE_MAX_LIMIT), MCP_HISTORY_TIMELINE_MAX_LIMIT));

      const url = `${base}/api/intelligence/v1/get-intel-timeline?${query}`;
      const auth = await buildAuthHeaders(context, 'GET', url, null);
      // No embedding on this path — one store read, so the tighter budget.
      const response = await fetch(url, {
        headers: { ...auth, 'User-Agent': 'worldmonitor-mcp-edge/1.0' },
        signal: AbortSignal.timeout(8_000),
      });
      await assertMcpToolFetchOk(response, {
        operation: 'get-intel-timeline',

View on GitHub (pinned to ffec79ac33)

Solutions

  1. Provide at least one of domain or country: domain must be one of 'conflict', 'military', 'energy'; country must be an ISO 3166-1 alpha-2 code.
  2. If you want all domains for a country, pass only country (e.g. country='US') — the handler applies the country index across all domains.
  3. If you want a cross-country domain view, pass only domain (e.g. domain='military').
  4. You can pass both domain AND country to narrow to one domain within one country.

Example fix

// before — no scope, throws immediately
tool: 'get_intel_timeline', params: { limit: 50 }
// after — scoped to military domain
tool: 'get_intel_timeline', params: { domain: 'military', limit: 50 }
Defensive patterns

Strategy: validation

Validate before calling

// Validate scope params BEFORE calling get_intel_timeline
const VALID_DOMAINS = ['conflict', 'military', 'energy'];
const domain = typeof params.domain === 'string' ? params.domain.trim() : '';
const country = typeof params.country === 'string' ? params.country.trim() : '';
if (!domain && !country) {
  throw new Error('Provide at least one of domain or country');
}
if (country && !/^[A-Z]{2}$/.test(country)) {
  throw new Error('country must be ISO 3166-1 alpha-2');
}
if (domain && !VALID_DOMAINS.includes(domain)) {
  throw new Error(`domain must be one of: ${VALID_DOMAINS.join(', ')}`);
}

Prevention

When it happens

Trigger: Calling get_intel_timeline with neither domain nor country provided (both omitted, empty strings, or whitespace-only). For example: params: {} or params: { limit: 100 } or params: { domain: ' ', country: '' }. The validation trims the values first, so whitespace-only strings are treated as absent.

Common situations: An agent or caller that calls get_intel_timeline with only optional params (from, to, limit) forgetting the required scope; passing a domain value outside the allowed set (e.g. domain='geopolitics') — note this does NOT trigger THIS error (the string is non-empty) but would fail server-side; copy-paste from a template that omitted the scope fields.

Related errors


AI-assisted analysis of koala73/worldmonitor@ffec79ac33 (2026-08-12). Data as JSON: /api/errors/68badc05d9cbad21. Report an issue: GitHub.