Skip to main content
Glama

tickerbot_scan

Every ticker matching a SQL WHERE clause. Right now, or with asof, as of any past date. The q grammar is a flat SQL WHERE over signal names: AND/OR/NOT, comparisons, numeric and string literals, custom signals by name. No JOIN or subqueries. With group_by the result is rollup rows, not tickers. Example: gap_up AND market_cap < 2000000000 AND NOT earnings_this_week.

Input Schema

TableJSON Schema
NameRequiredDescriptionDefault
qYesSQL WHERE expression. Max 4000 chars; semicolons, comments and write keywords are rejected. Your custom signals are valid here — each expands to its SQL at run time.
dirNoSort direction.desc
asofNoOptional. Target moment as `YYYY-MM-DD` (that day's close) or an ISO timestamp (that intraday moment) — the same read as it stood then, unlimited depth. Full contract under As of a past date.
fullNoReturn every signal instead of the default set. Mutually exclusive with `columns` — passing both is a 400.
limitNoPage size. Max 100. Aggregate mode does not paginate — it sets `truncated: true` when groups were cut, so sort with `order` to keep the ones you want.
orderNoSignal to sort by. In aggregate mode the default is the count alias `tickers` — or, with a custom `select`, the last item's alias — sorted NULLS LAST with the group keys as tiebreak.change_1d_pct
cursorNoOpaque cursor from the previous response's `next_cursor`. Row mode only.
havingNoFilter the aggregate rows (requires `group_by`). Custom signals are valid here too.
selectNoAggregate output items (requires `group_by`). Default: the group keys + `COUNT(*) AS tickers`. Supports count/avg/sum/min/max/stddev/string_agg/bool_and/bool_or plus `FILTER (WHERE …)`, and your custom signals inside expressions. Alias with `AS`; a last item without one is a 400.
columnsNoExtra signals per row, ADDITIVE — the defaults are always present (ticker, name, asset_class, asset_type, price, change_1d_pct, gap_pct, relative_volume, market_cap). `fields` accepted as an alias.
group_byNoAGGREGATE MODE: 1–6 group keys (signals, expressions, or one of your custom signals as a boolean key). Results become rollup rows. Name a key with `AS` to choose its JSON key (`market_cap > 1e11 AS mega`); an un-named expression is named for you rather than returned as `?column?`. Incompatible with `columns`/`full`/`cursor`; works with `asof`.
intervalNoGrain the past state is reconstructed at: `1m`, `1h`, `1d`, or `auto` (default). Only valid alongside `asof` — a live read with `interval` is a 400. Details under As of a past date.auto
universeNoSlug of a system universe (`top_10`, `top_100`) or one of your own. Omitted, the scan runs across all ~21,072 tracked tickers.
asset_classNoOne or more asset classes — slug or comma-separated list (`stocks`, `rates`, `crypto`, `fx`). Validated for shape, not against a fixed list, so a well-formed class we don't track simply matches nothing. Echoed in `query`.

Output Schema

TableJSON Schema
NameRequiredDescriptionDefault
_metaNo`null_coverage` reports, per signal in the predicate, how many in-scope rows are NULL and therefore never evaluated — absence from `results` means "no value", not "did not match". `scope` additionally describes an explicit `universe`.
as_ofYesServer time this response was assembled (ISO 8601).
countYesRows in this page.
queryYesYour query, echoed — `q`, `order`, `dir`, `limit`, and any scope.
resultsYesOne row per match — every signal on the schema page, plus any you named.
truncatedNoAggregate mode only (`group_by`): `true` when the rollup stopped at its row cap. Aggregate responses are unpaged, so `next_cursor` is absent there.
next_cursorNoOpaque token for the next page; `null` on the last page. Pass it back as `cursor`.

Schema Changelog

Changes observed during successful MCP inspections.

  1. Changed1 schema field changed
    • changedInput schema / properties / universe / description
      Previous value: -"Slug of a system universe (`top_10`, `top_100`) or one of your own. Omitted, the scan runs across all ~21,066 tracked tickers."New value: +"Slug of a system universe (`top_10`, `top_100`) or one of your own. Omitted, the scan runs across all ~21,072 tracked tickers."
  2. Changed1 schema field changed
    • changedInput schema / properties / universe / description
      Previous value: -"Slug of a system universe (`top_10`, `top_100`) or one of your own. Omitted, the scan runs across all ~21,053 tracked tickers."New value: +"Slug of a system universe (`top_10`, `top_100`) or one of your own. Omitted, the scan runs across all ~21,066 tracked tickers."
  3. Changed1 schema field changed
    • changedInput schema / properties / universe / description
      Previous value: -"Slug of a system universe (`top_10`, `top_100`) or one of your own. Omitted, the scan runs across all ~21,040 tracked tickers."New value: +"Slug of a system universe (`top_10`, `top_100`) or one of your own. Omitted, the scan runs across all ~21,053 tracked tickers."
  4. Changed1 schema field changed
    • changedOutput schema / (root)
      Previous value: -nullNew value: +{
      +  "additionalProperties": false,
      +  "properties": {
      +    "_meta": {
      +      "description": "`null_coverage` reports, per signal in the predicate, how many in-scope rows are NULL and therefore never evaluated — absence from `results` means \"no value\", not \"did not match\". `scope` additionally describes an explicit `universe`.",
      +      "type": "object"
      +    },
      +    "as_of": {
      +      "description": "Server time this response was assembled (ISO 8601).",
      +      "type": "string"
      +    },
      +    "count": {
      +      "description": "Rows in this page.",
      +      "type": "number"
      +    },
      +    "next_cursor": {
      +      "description": "Opaque token for the next page; `null` on the last page. Pass it back as `cursor`.",
      +      "type": "string"
      +    },
      +    "query": {
      +      "description": "Your query, echoed — `q`, `order`, `dir`, `limit`, and any scope.",
      +      "type": "object"
      +    },
      +    "results": {
      +      "description": "One row per match — every signal on the schema page, plus any you named.",
      +      "items": {
      +        "type": "string"
      +      },
      +      "type": "array"
      +    },
      +    "truncated": {
      +      "description": "Aggregate mode only (`group_by`): `true` when the rollup stopped at its row cap. Aggregate responses are unpaged, so `next_cursor` is absent there.",
      +      "type": "boolean"
      +    }
      +  },
      +  "required": [
      +    "as_of",
      +    "query",
      +    "count",
      +    "results"
      +  ],
      +  "type": "object"
      +}
  5. Changed1 schema field changed
    • changedInput schema / properties / universe / description
      Previous value: -"Slug of a system universe (`top_10`, `top_100`) or one of your own. Omitted, the scan runs across all ~21,033 tracked tickers."New value: +"Slug of a system universe (`top_10`, `top_100`) or one of your own. Omitted, the scan runs across all ~21,040 tracked tickers."
  6. Changed1 schema field changed
    • changedInput schema / properties / universe / description
      Previous value: -"Slug of a system universe (`top_10`, `top_100`) or one of your own. Omitted, the scan runs across all ~21,008 tracked tickers."New value: +"Slug of a system universe (`top_10`, `top_100`) or one of your own. Omitted, the scan runs across all ~21,033 tracked tickers."
  7. Changed18 schema fields changed
    • changedInput schema / properties / asof / description
      Previous value: -"Optional YYYY-MM-DD or ISO timestamp for a historical scan. Unlimited depth on every plan."New value: +"Optional. Target moment as `YYYY-MM-DD` (that day's close) or an ISO timestamp (that intraday moment) — the same read as it stood then, unlimited depth. Full contract under As of a past date."
    • addedInput schema / properties / asset_class
      Added value: +{
      +  "description": "One or more asset classes — slug or comma-separated list (`stocks`, `rates`, `crypto`, `fx`). Validated for shape, not against a fixed list, so a well-formed class we don't track simply matches nothing. Echoed in `query`.",
      +  "type": "string"
      +}
    • addedInput schema / properties / columns
      Added value: +{
      +  "description": "Extra signals per row, ADDITIVE — the defaults are always present (ticker, name, asset_class, asset_type, price, change_1d_pct, gap_pct, relative_volume, market_cap). `fields` accepted as an alias.",
      +  "type": "string"
      +}
    • changedInput schema / properties / cursor / description
      Previous value: -"Opaque cursor (row mode only)."New value: +"Opaque cursor from the previous response's `next_cursor`. Row mode only."
    • addedInput schema / properties / dir / default
      Added value: +"desc"
    • removedInput schema / properties / fields
      Removed value: -{
      -  "description": "Comma-separated extra columns to include (row mode only).",
      -  "type": "string"
      -}
    • addedInput schema / properties / full / default
      Added value: +false
    • changedInput schema / properties / full / description
      Previous value: -"Row mode: return the FULL wide row for each match (every column) instead of the slim default projection."New value: +"Return every signal instead of the default set. Mutually exclusive with `columns` — passing both is a 400."
    • changedInput schema / properties / group_by / description
      Previous value: -"AGGREGATE MODE: 1–6 comma-separated group keys (columns or expressions, e.g. `sector`). Results become rollup rows instead of tickers. Alias a key with `AS` to name its JSON key; un-named expressions are named for you."New value: +"AGGREGATE MODE: 1–6 group keys (signals, expressions, or one of your custom signals as a boolean key). Results become rollup rows. Name a key with `AS` to choose its JSON key (`market_cap > 1e11 AS mega`); an un-named expression is named for you rather than returned as `?column?`. Incompatible with `columns`/`full`/`cursor`; works with `asof`."
    • changedInput schema / properties / having / description
      Previous value: -"Aggregate filter (requires group_by). Example: `COUNT(*) >= 10`."New value: +"Filter the aggregate rows (requires `group_by`). Custom signals are valid here too."
    • addedInput schema / properties / interval
      Added value: +{
      +  "default": "auto",
      +  "description": "Grain the past state is reconstructed at: `1m`, `1h`, `1d`, or `auto` (default). Only valid alongside `asof` — a live read with `interval` is a 400. Details under As of a past date.",
      +  "enum": [
      +    "1m",
      +    "1h",
      +    "1d",
      +    "auto"
      +  ],
      +  "type": "string"
      +}
    • addedInput schema / properties / limit / default
      Added value: +50
    • changedInput schema / properties / limit / description
      Previous value: -"Page size. Max 100. Default 50. Aggregate mode does not paginate — response sets `truncated: true` when groups were cut."New value: +"Page size. Max 100. Aggregate mode does not paginate — it sets `truncated: true` when groups were cut, so sort with `order` to keep the ones you want."
    • addedInput schema / properties / order / default
      Added value: +"change_1d_pct"
    • changedInput schema / properties / order / description
      Previous value: -"Sort column. Default: the 1-day change column (rows) / tickers (aggregate)."New value: +"Signal to sort by. In aggregate mode the default is the count alias `tickers` — or, with a custom `select`, the last item's alias — sorted NULLS LAST with the group keys as tiebreak."
    • changedInput schema / properties / q / description
      Previous value: -"SQL WHERE expression. Max 4000 chars."New value: +"SQL WHERE expression. Max 4000 chars; semicolons, comments and write keywords are rejected. Your custom signals are valid here — each expands to its SQL at run time."
    • changedInput schema / properties / select / description
      Previous value: -"Aggregate output items (requires group_by). Default: group keys + COUNT(*) AS tickers. Aggregates: count/avg/sum/min/max/stddev/string_agg + FILTER (WHERE …). Alias items with AS. Example: `sector, COUNT(*) AS n, AVG(rsi_14) AS avg_rsi`."New value: +"Aggregate output items (requires `group_by`). Default: the group keys + `COUNT(*) AS tickers`. Supports count/avg/sum/min/max/stddev/string_agg/bool_and/bool_or plus `FILTER (WHERE …)`, and your custom signals inside expressions. Alias with `AS`; a last item without one is a 400."
    • changedInput schema / properties / universe / description
      Previous value: -"Optional universe slug."New value: +"Slug of a system universe (`top_10`, `top_100`) or one of your own. Omitted, the scan runs across all ~21,008 tracked tickers."
  8. Changed1 schema field changed
    • changedInput schema / properties / order / description
      Previous value: -"Sort column. Default day_change_pct (rows) / tickers (aggregate)."New value: +"Sort column. Default: the 1-day change column (rows) / tickers (aggregate)."
  9. Changed1 schema field changed
    • changedInput schema / properties / group_by / description
      Previous value: -"AGGREGATE MODE: 1–6 comma-separated group keys (columns or expressions, e.g. `sector`). Results become rollup rows instead of tickers."New value: +"AGGREGATE MODE: 1–6 comma-separated group keys (columns or expressions, e.g. `sector`). Results become rollup rows instead of tickers. Alias a key with `AS` to name its JSON key; un-named expressions are named for you."
  10. Changed1 schema field changed
    • addedInput schema / properties / full
      Added value: +{
      +  "description": "Row mode: return the FULL wide row for each match (every column) instead of the slim default projection.",
      +  "type": "boolean"
      +}
  11. Changed1 schema field changed
    • changedInput schema / properties / asof / description
      Previous value: -"Optional YYYY-MM-DD or ISO timestamp for a historical scan. Free plan: last 30 days; paid: unlimited."New value: +"Optional YYYY-MM-DD or ISO timestamp for a historical scan. Unlimited depth on every plan."
  12. Changed8 schema fields changed
    • changedInput schema / properties / asof / description
      Previous value: -"Optional YYYY-MM-DD or ISO timestamp for a historical scan."New value: +"Optional YYYY-MM-DD or ISO timestamp for a historical scan. Free plan: last 30 days; paid: unlimited."
    • changedInput schema / properties / cursor / description
      Previous value: -"Opaque cursor."New value: +"Opaque cursor (row mode only)."
    • changedInput schema / properties / fields / description
      Previous value: -"Comma-separated extra columns to include."New value: +"Comma-separated extra columns to include (row mode only)."
    • addedInput schema / properties / group_by
      Added value: +{
      +  "description": "AGGREGATE MODE: 1–6 comma-separated group keys (columns or expressions, e.g. `sector`). Results become rollup rows instead of tickers.",
      +  "type": "string"
      +}
    • addedInput schema / properties / having
      Added value: +{
      +  "description": "Aggregate filter (requires group_by). Example: `COUNT(*) >= 10`.",
      +  "type": "string"
      +}
    • changedInput schema / properties / limit / description
      Previous value: -"Page size. Max 100. Default 50."New value: +"Page size. Max 100. Default 50. Aggregate mode does not paginate — response sets `truncated: true` when groups were cut."
    • changedInput schema / properties / order / description
      Previous value: -"Sort column. Default day_change_pct."New value: +"Sort column. Default day_change_pct (rows) / tickers (aggregate)."
    • addedInput schema / properties / select
      Added value: +{
      +  "description": "Aggregate output items (requires group_by). Default: group keys + COUNT(*) AS tickers. Aggregates: count/avg/sum/min/max/stddev/string_agg + FILTER (WHERE …). Alias items with AS. Example: `sector, COUNT(*) AS n, AVG(rsi_14) AS avg_rsi`.",
      +  "type": "string"
      +}
  13. Changed1 schema field changed
    • changedInput schema / properties / asof / description
      Previous value: -"Optional YYYY-MM-DD for historical scan."New value: +"Optional YYYY-MM-DD or ISO timestamp for a historical scan."
  14. First observed

TDQS

A3.7/5.0
Behavior3/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

With no annotations provided, the description carries the full burden and does disclose meaningful behavior: temporal reads via asof, the flat/restricted grammar (no JOIN or subqueries), and the mode shift to rollup rows with group_by. It does not explicitly state that this is a read-only operation, nor cover side effects, rate limits, or error behavior, though the schema covers most error contracts.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness5/5

Is the description appropriately sized, front-loaded, and free of redundancy?

Five tight sentences with no filler: the core purpose is front-loaded first, followed by grammar constraints, the group_by caveat, and a concrete example. Every sentence carries distinct information and none repeats the schema.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness4/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

For a complex 14-parameter tool with two major modes (row and aggregate) plus asof, the description covers the headline semantics well: the query grammar, temporal reads, and aggregate-mode behavior. With a rich output schema present and 100% parameter coverage, the remaining concepts (pagination, having/select, universe scoping) are adequately handled by the schema, so the description selects the right high-value concepts to explain.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters4/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema coverage is 100%, so the baseline is 3, but the description clearly exceeds it: it explains the q grammar in detail (AND/OR/NOT, comparisons, literals, custom signal expansion, no JOIN/subqueries) and adds meaning to group_by and asof that the schema's short field descriptions only hint at. The example ties q, signals, and semantics together in a way the schema alone cannot.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose4/5

Does the description clearly state what the tool does and how it differs from similar tools?

The description states a clear resource (tickers) and action (return every ticker matching a SQL WHERE clause), with a concrete example. It distinguishes itself behaviorally by noting that group_by produces rollup rows instead of tickers, which separates it from listing/getting tools among the siblings, though it never names a sibling explicitly and the verb is implied rather than stated.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines3/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

Usage is implied through the grammar explanation and the concrete example (`gap_up AND market_cap < 2000000000 AND NOT earnings_this_week`), which conveys that this tool screens tickers by signal conditions. However, there is no explicit when-to-use versus when-not-to-use guidance, no mention of alternatives like subscribe_scan or list_tickers, and no exclusions stated.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

Try in Browser

Glama MCP Gateway

Add one secure layer between your agents and this server.