{
 "server": "mcpdata",
 "transport": "streamable-http",
 "url": "https://<instance>.mcpdata.org/mcp",
 "auth": "Authorization: Bearer <API key>",
 "tools": [
  {
   "kind": "tool",
   "name": "list_tables",
   "uri": null,
   "args": [],
   "doc": "List every table in CDB's registry: name, row count, last-updated time.\nCall this first when you don't already know a table's exact name."
  },
  {
   "kind": "tool",
   "name": "describe_table",
   "uri": null,
   "args": [
    {
     "name": "table_name",
     "type": "str",
     "required": true,
     "default": null
    }
   ],
   "doc": "Describe one table's columns (name + dtype) and row count. Always call\nthis before querying a table you haven't seen before -- guessing column\nnames or types wastes a round trip on a QuerySpecError."
  },
  {
   "kind": "tool",
   "name": "query",
   "uri": null,
   "args": [
    {
     "name": "table_name",
     "type": "str",
     "required": true,
     "default": null
    },
    {
     "name": "columns",
     "type": "list[str] | None",
     "required": false,
     "default": "None"
    },
    {
     "name": "filters",
     "type": "list[dict] | None",
     "required": false,
     "default": "None"
    },
    {
     "name": "group_by",
     "type": "list[str] | None",
     "required": false,
     "default": "None"
    },
    {
     "name": "agg",
     "type": "list[dict] | None",
     "required": false,
     "default": "None"
    },
    {
     "name": "sort",
     "type": "list[dict] | None",
     "required": false,
     "default": "None"
    },
    {
     "name": "limit",
     "type": "int | None",
     "required": false,
     "default": "None"
    },
    {
     "name": "cursor",
     "type": "str | None",
     "required": false,
     "default": "None"
    }
   ],
   "doc": "Run a structured query against one table. No raw SQL -- build the query\nfrom these arguments instead:\n\n- columns: which columns to return (omit for all columns).\n- filters: list of {\"column\": str, \"op\": str, \"value\": ...}. op is one of\n  eq/ne/gt/gte/lt/lte/in/not_in/like/is_null/is_not_null/between.\n- group_by: list of column names to group by.\n- agg: required if group_by is set. list of\n  {\"func\": \"sum\"/\"avg\"/\"count\"/\"min\"/\"max\"/\"stdev\"/\"var\", \"column\": str,\n  \"alias\": optional str}.\n- sort: list of {\"column\": str, \"desc\": bool}.\n- limit: max rows to return this call (default 1000, hard cap 10000). A page\n  is also capped at about 64 KB of rows, so wide rows give fewer per page.\n- cursor: pass back a previous response's next_cursor, with the SAME other\n  arguments, to get the next page.\n\nThe response always includes truncated (bool) and next_cursor (str or\nnull) -- check truncated before assuming you have the whole answer; when\nknown, total_rows is the full result's size. Pages of a plain table read\ncost the same however far in they are; a filtered/sorted/grouped result is\nkept on the server for 15 minutes of paging (up to 100,000 rows -- past\nthat, narrow it or use export_query). See cdb://skills/query-guide."
  },
  {
   "kind": "tool",
   "name": "list_views",
   "uri": null,
   "args": [],
   "doc": "List the stored views you can run with query_view: name, @parameters (types and defaults) and description.\nA view is saved SQL -- joins, CASE, UNION, AS OF time travel, multi-step scripts -- so it answers questions the\none-table query tool can't."
  },
  {
   "kind": "tool",
   "name": "query_view",
   "uri": null,
   "args": [
    {
     "name": "name",
     "type": "str",
     "required": true,
     "default": null
    },
    {
     "name": "params",
     "type": "dict | None",
     "required": false,
     "default": "None"
    },
    {
     "name": "limit",
     "type": "int | None",
     "required": false,
     "default": "None"
    },
    {
     "name": "cursor",
     "type": "str | None",
     "required": false,
     "default": "None"
    }
   ],
   "doc": "Run a stored view and return its rows, paged like query(): at most limit rows (default 1000, hard cap\n10000) and about 64 KB per page, with truncated / next_cursor / total_rows.\n\n- name: the view's name, from list_views (e.g. \"reports.daily_pnl\").\n- params: values for its @parameters, e.g. {\"from\": \"2026-01-01\", \"desk\": \"Credit\"}; a parameter with a\n  default can be left out.\n- cursor: a previous response's next_cursor (same name and params) for the next page. The view runs once; its\n  result is kept on the server for 15 minutes of paging (up to 100,000 rows).\n\nWorks with a Read key. To make a new view, create_view (ReadWrite)."
  },
  {
   "kind": "tool",
   "name": "export_query",
   "uri": null,
   "args": [
    {
     "name": "table_name",
     "type": "str",
     "required": true,
     "default": null
    },
    {
     "name": "columns",
     "type": "list[str] | None",
     "required": false,
     "default": "None"
    },
    {
     "name": "filters",
     "type": "list[dict] | None",
     "required": false,
     "default": "None"
    },
    {
     "name": "group_by",
     "type": "list[str] | None",
     "required": false,
     "default": "None"
    },
    {
     "name": "agg",
     "type": "list[dict] | None",
     "required": false,
     "default": "None"
    }
   ],
   "doc": "Export the FULL (uncapped) result of a structured query to a Parquet\nfile plus a JSON manifest, and return their paths. Use this instead of\npaging through query() when you genuinely need every row, not a sample --\ne.g. before bulk-processing a large result outside CDB. Takes the same\nfilters/group_by/agg arguments as query(). Needs the ReadWrite role (it\nwrites a file on the server)."
  },
  {
   "kind": "tool",
   "name": "share_dataset",
   "uri": null,
   "args": [
    {
     "name": "table_name",
     "type": "str",
     "required": true,
     "default": null
    },
    {
     "name": "columns",
     "type": "list[str] | None",
     "required": false,
     "default": "None"
    },
    {
     "name": "filters",
     "type": "list[dict] | None",
     "required": false,
     "default": "None"
    },
    {
     "name": "group_by",
     "type": "list[str] | None",
     "required": false,
     "default": "None"
    },
    {
     "name": "agg",
     "type": "list[dict] | None",
     "required": false,
     "default": "None"
    }
   ],
   "doc": "Export a structured query's result as a shareable artifact and return\na share_id another agent can pass to import_shared to get their own real,\nqueryable copy. Takes the same filters/group_by/agg arguments as query().\nNeeds the ReadWrite role (it writes a file on the server)."
  },
  {
   "kind": "tool",
   "name": "import_shared",
   "uri": null,
   "args": [
    {
     "name": "share_id",
     "type": "str",
     "required": true,
     "default": null
    },
    {
     "name": "new_table_name",
     "type": "str | None",
     "required": false,
     "default": "None"
    }
   ],
   "doc": "Import a dataset another agent shared via share_dataset, given its\nshare_id. Ingests it as a real table in your own tenant (via the same\ningest pipeline any other data upload uses) and returns the new table's\nname -- query it like any other table afterward."
  },
  {
   "kind": "tool",
   "name": "create_table",
   "uri": null,
   "args": [
    {
     "name": "name",
     "type": "str",
     "required": true,
     "default": null
    },
    {
     "name": "kind",
     "type": "str",
     "required": true,
     "default": null
    },
    {
     "name": "columns",
     "type": "list[dict]",
     "required": true,
     "default": null
    },
    {
     "name": "shard_by",
     "type": "str | None",
     "required": false,
     "default": "None"
    },
    {
     "name": "width",
     "type": "int",
     "required": false,
     "default": "1"
    },
    {
     "name": "rows",
     "type": "list[dict] | None",
     "required": false,
     "default": "None"
    },
    {
     "name": "request_id",
     "type": "str | None",
     "required": false,
     "default": "None"
    }
   ],
   "doc": "Create a table of your own to keep structured data in -- then query it with query/describe_table like any\ntable. Names must be under agent.* (e.g. agent.findings, agent.prices.daily); nothing else can be written.\n\n- kind: \"log\" (append_rows adds rows; reads return every row ever appended -- events, findings, records) or\n  \"snapshot\" (replace_rows writes the full current contents; reads return only the latest -- a current list,\n  a reference table). Every write is kept as a version, so history is never lost.\n- columns: [{\"name\": \"price\", \"type\": \"double\"}, ...]; types: string, int64, double, bool, datetime.\n- shard_by (snapshot only): a column such as \"book\" -- each key's rows are kept and replaced on their own, so\n  replace_rows with book B12's rows updates B12 and leaves every other book as it was.\n- width (log only, default 1): write every append as exactly this many shards -- only worth raising for very\n  large appends, which then read in parallel; small appends at width > 1 just make more small files.\n- rows: optional first rows (objects keyed by column name).\n- request_id: optional; repeating a call with the same id (e.g. after a timeout) won't write twice."
  },
  {
   "kind": "tool",
   "name": "append_rows",
   "uri": null,
   "args": [
    {
     "name": "table",
     "type": "str",
     "required": true,
     "default": null
    },
    {
     "name": "rows",
     "type": "list[dict]",
     "required": true,
     "default": null
    },
    {
     "name": "add_columns",
     "type": "list[dict] | None",
     "required": false,
     "default": "None"
    },
    {
     "name": "drop_columns",
     "type": "list[str] | None",
     "required": false,
     "default": "None"
    },
    {
     "name": "request_id",
     "type": "str | None",
     "required": false,
     "default": "None"
    }
   ],
   "doc": "Append rows to one of your log tables (agent.*). rows: objects keyed by column name (a missing column is\nNULL). At most 10,000 rows per call -- batch several records per call rather than one call per record.\nadd_columns: [{\"name\", \"type\"}] to add new columns (earlier rows read them as NULL); drop_columns: names to stop\nwriting (earlier rows keep their values). A column's type can never change. request_id: repeat-safe retries."
  },
  {
   "kind": "tool",
   "name": "replace_rows",
   "uri": null,
   "args": [
    {
     "name": "table",
     "type": "str",
     "required": true,
     "default": null
    },
    {
     "name": "rows",
     "type": "list[dict]",
     "required": true,
     "default": null
    },
    {
     "name": "add_columns",
     "type": "list[dict] | None",
     "required": false,
     "default": "None"
    },
    {
     "name": "drop_columns",
     "type": "list[str] | None",
     "required": false,
     "default": "None"
    },
    {
     "name": "remove_keys",
     "type": "list | None",
     "required": false,
     "default": "None"
    },
    {
     "name": "request_id",
     "type": "str | None",
     "required": false,
     "default": "None"
    }
   ],
   "doc": "Replace the contents of one of your snapshot tables (agent.*): rows are the new full contents; reads return\nonly this latest version (earlier versions are kept as history). For a table created with shard_by, only the keys\npresent in rows are replaced -- every other key keeps its rows; remove_keys: keys to empty. add_columns /\ndrop_columns as in append_rows; types never change. At most 10,000 rows per call. request_id: repeat-safe."
  },
  {
   "kind": "tool",
   "name": "create_view",
   "uri": null,
   "args": [
    {
     "name": "name",
     "type": "str",
     "required": true,
     "default": null
    },
    {
     "name": "select_sql",
     "type": "str",
     "required": true,
     "default": null
    },
    {
     "name": "params",
     "type": "list[dict] | None",
     "required": false,
     "default": "None"
    },
    {
     "name": "description",
     "type": "str | None",
     "required": false,
     "default": "None"
    }
   ],
   "doc": "Create (or replace) a stored view \u2014 a named, saved query that reports and other queries reuse. This is how\nyou turn a user's natural-language request into a durable definition: translate what they asked into CDB SQL for\nselect_sql, then call this. Use list_tables / describe_table first to get exact table and column names rather\nthan guessing.\n\n- name: the view's name, optionally namespaced, e.g. \"reports.daily_pnl\".\n- select_sql: the query the view returns, e.g. \"SELECT underlying, SUM(notional) AS notional FROM DeribitTrades\n  WHERE ts >= @from GROUP BY underlying\". It may reference any @parameters declared in params.\n- params: optional [{\"name\",\"type\",\"default\"?}] (type: STRING/INT/DOUBLE/BOOL/DATETIME) so a report can bind\n  them, e.g. [{\"name\":\"from\",\"type\":\"DATETIME\"}].\n- description: optional human-readable description.\n\nNeeds the ReadWrite role. Then create_report(view=name, ...) renders and schedules it. Prefer a GROUP BY /\naggregated view over raw rows \u2014 a report should return a small, already-summarised result. Read the\ncdb://skills/view-guide resource for CDB's SQL dialect and view syntax before composing select_sql; if a call\nfails, the engine's error says what to fix."
  },
  {
   "kind": "tool",
   "name": "drop_view",
   "uri": null,
   "args": [
    {
     "name": "name",
     "type": "str",
     "required": true,
     "default": null
    }
   ],
   "doc": "Delete a stored view by name. Any report pointing at it will fail until the view is recreated."
  },
  {
   "kind": "tool",
   "name": "list_reports",
   "uri": null,
   "args": [],
   "doc": "List this instance's scheduled reports, each with its schedules and recent runs. A report is a saved\nview rendered on a cadence and emailed. Call this before scheduling or running one, to get its report_id."
  },
  {
   "kind": "tool",
   "name": "create_report",
   "uri": null,
   "args": [
    {
     "name": "name",
     "type": "str",
     "required": true,
     "default": null
    },
    {
     "name": "view",
     "type": "str",
     "required": true,
     "default": null
    },
    {
     "name": "params",
     "type": "dict | None",
     "required": false,
     "default": "None"
    },
    {
     "name": "format",
     "type": "str",
     "required": false,
     "default": "'html'"
    },
    {
     "name": "chart",
     "type": "dict | None",
     "required": false,
     "default": "None"
    },
    {
     "name": "pivot",
     "type": "dict | None",
     "required": false,
     "default": "None"
    }
   ],
   "doc": "Define a report: a stored view (its definition, which must already exist -- see SHOW VIEWS / the workbench)\nrendered to `format` (html, csv or xlsx). params binds the view's @parameters, e.g. {\"desk\": \"EMEA\"}. Returns\n{\"report_id\"}. This only defines the report; use schedule_report to send it on a cadence or run_report to send\nit once now. The report's data stays a live view -- each run re-queries it.\n\nchart (html only): add an interactive chart above the table, over the same rows. It is the chart block body:\n{\"chart\": \"bar\"|\"line\"|\"area\"|\"scatter\"|\"pie\"|\"histogram\", \"x\": <column>, \"y\": <column>, \"color\": <column>?,\n\"title\": <str>?}. e.g. {\"chart\":\"bar\",\"x\":\"strategy\",\"y\":\"notional\"}. For pie, y is the slice size and x (or\ncolor) the category; for histogram, only x is needed (it is binned and counted). Charts are self-contained (the\nVega library is inlined, so the file opens offline) but need a browser that runs scripts; email clients don't, so\nthe table always carries the numbers, as do csv/xlsx. For the full\ndata -> views -> reports -> pivot workflow and when a pivot makes sense, read cdb://skills/reporting-guide.\n\npivot (optional): attach a pivot preset so the report shows an \"Open in pivot\" button that opens the workbench\npivot pre-arranged. A pivot-config fragment, e.g.\n{\"rows\":[\"Category\"],\"columns\":[\"Gender\"],\"values\":[[\"SalesAmount\",\"sum\"]],\"table\":\"aw.InternetSales\"};\nomit table/view to pivot the report's own view. Reports without a pivot preset show no pivot button."
  },
  {
   "kind": "tool",
   "name": "schedule_report",
   "uri": null,
   "args": [
    {
     "name": "report_id",
     "type": "str",
     "required": true,
     "default": null
    },
    {
     "name": "cron",
     "type": "str",
     "required": true,
     "default": null
    },
    {
     "name": "recipients",
     "type": "list[str]",
     "required": true,
     "default": null
    },
    {
     "name": "enabled",
     "type": "bool",
     "required": false,
     "default": "True"
    }
   ],
   "doc": "Schedule a report by cron (5 fields \"min hour day-of-month month day-of-week\", or @daily/@weekly/@hourly;\nUTC). recipients are emailed the rendered report each run. e.g. cron \"0 8 * * 1\" = every Monday 08:00 UTC.\nReturns {\"schedule_id\"}. Scheduling is an outbound email on a timer -- set recipients deliberately."
  },
  {
   "kind": "tool",
   "name": "run_report",
   "uri": null,
   "args": [
    {
     "name": "report_id",
     "type": "str",
     "required": true,
     "default": null
    },
    {
     "name": "recipients",
     "type": "list[str] | None",
     "required": false,
     "default": "None"
    }
   ],
   "doc": "Run a report once now: re-query its view, render it, and (if recipients are given) email it. Returns the run\nresult {\"status\", \"rows\", ...}. Use this to preview a report before scheduling it, or for an ad-hoc send."
  },
  {
   "kind": "tool",
   "name": "list_report_runs",
   "uri": null,
   "args": [
    {
     "name": "report_id",
     "type": "str",
     "required": true,
     "default": null
    },
    {
     "name": "limit",
     "type": "int",
     "required": false,
     "default": "20"
    }
   ],
   "doc": "The run history of one report (newest first): status (ok/failed/running), row count, duration, any error.\nThis is how you check whether scheduled sends are succeeding."
  },
  {
   "kind": "tool",
   "name": "delete_report",
   "uri": null,
   "args": [
    {
     "name": "report_id",
     "type": "str",
     "required": true,
     "default": null
    }
   ],
   "doc": "Delete a report and all its schedules. Past run records and already-rendered output files are left alone."
  },
  {
   "kind": "resource",
   "name": "query_guide",
   "uri": "cdb://skills/query-guide",
   "args": [],
   "doc": "Static, hand-authored guidance on querying CDB efficiently: when to filter, when to aggregate instead of fetching raw rows, how pagination and truncation work, and when to reach for export_query/share_dataset."
  },
  {
   "kind": "resource",
   "name": "view_guide",
   "uri": "cdb://skills/view-guide",
   "args": [],
   "doc": "How to write a correct CDB view with create_view: the view DDL, CDB's SQL dialect (aggregates, WHERE, GROUP BY/HAVING/ORDER BY, JOIN, AS OF time-travel with #date# literals), view @parameters, and how to shape a good report view (aggregate, parameterise the date range). Read this before composing select_sql for create_view."
  },
  {
   "kind": "resource",
   "name": "reporting_guide",
   "uri": "cdb://skills/reporting-guide",
   "args": [],
   "doc": "The end-to-end recipe for turning data into a full set of reports: upload (create_table/append_rows, or an out-of-band load), shape aggregated parameterised views (create_view), create reports with charts (create_report), add a pivot preset WHERE IT MAKES SENSE (create_report pivot=, base-table source), and schedule/run them. Read this before building a reporting dataset."
  },
  {
   "kind": "resource",
   "name": "schema_catalog",
   "uri": "cdb://schema",
   "args": [],
   "doc": "Every table currently in the registry, with row counts -- a quick catalog to scan before drilling into one table's own schema."
  },
  {
   "kind": "resource",
   "name": "table_schema",
   "uri": "cdb://schema/{table_name}",
   "args": [
    {
     "name": "table_name",
     "type": "str",
     "required": true,
     "default": null
    }
   ],
   "doc": "One table's columns, types, and row count -- generated live from the same data describe_table exposes, formatted for a quick read."
  }
 ]
}