Connect your agents to Materialize with built-in MCP servers
July 22, 2026

Materialize is an agent-native platform, and that means different things for different agents. A coding agent operates the platform itself: it models data, deploys changes, and works out why something broke, without a human driving each step. An application agent acts on the data inside it, reading a live view of the business and deciding what to do next. Each job needs its own tools, wired to the live state of the platform. Materialize now ships with two MCP servers built directly into the platform, one for building agents on you r data and one for operating the platform.
Both run inside the database itself, not as a sidecar in front of it, and both are available now in public preview. The MCP protocol handler lives inside Materialize's HTTP layer, on the same server that serves the SQL HTTP API, and every tool call executes against the same query adapter that pgwire connections use.
Two servers, two jobs
Both servers speak JSON-RPC 2.0 over HTTP and support the standard MCP initialize, tools/list, and tools/call methods, so any compliant client works out of the box. They differ only in the tools they expose, a small set tailored to each use case.
The agent server (/api/mcp/agent) is for your data products, the live views you have curated over your business. An agent discovers them, reads what each one holds, and queries them, including joins across them. This is how you give an agent the context it acts on: the current state of your customers, orders, and inventory, joined into the nouns your business actually reasons about and served straight from the database that keeps them fresh. The agent reads the operational state of the business as it is right now, and because Materialize maintains every data product incrementally, that state stays consistent across all of them at a single point in time.
The developer server (/api/mcp/developer) is for your system catalog. It gives read-only access to the `mz_*` tables, so an assistant can answer operational questions about the platform itself: why a view is stale, how much memory a cluster is using, or what you can drop to save money. Where the agent server hands an agent the state of your business, the developer server hands it the state of the system serving that business.
What the agent server exposes
A data product is a view you already maintain: a materialized view, or a plain view with at least one index. Any such view a role can SELECT becomes a data product that role can query; non-indexed plain views are left out so a query never triggers a full recompute. Add a comment and it becomes the description the model reads when it decides which data product to query.
1 | |
2 | |
3 | |
4 | |
5 | |
6 | |
7 | |
8 | |
9 | |
10 | |
11 | |
12 | |
13 | |
14 | |
15 | |
16 | |
17 | |
18 | |
19 | |
20 | |
That is the whole definition, written in the SQL you already write. The agent discovers it with a get_data_products tool call, reads the comment to know what it holds, and queries it. Access follows the role you connect with.
The agent's toolset is your database, live. Which data products it can see, the schema of each one, and what it is allowed to touch all come straight from the catalog and follow the SQL grants you already manage. Grant a role SELECT on customer_360 and the data product appears on that role's next tool call, its schema matching the view. Revoke it and the product disappears. The schema itself is computed live by a system view that maps each column's SQL type to its JSON Schema type and flags which columns are indexed, so the model reads a description that matches the view as it is defined right now and knows which columns it can filter on cheaply. An agent reaches exactly the objects its role can SELECT, on clusters it has USAGE on, checked the same way as for every other client. Governing what an agent can do is the RBAC you already run.
Reads route themselves. When an agent reads a data product, Materialize runs the query on the cluster whose index already holds the answer, so the read hits a maintained arrangement. If the role lacks USAGE on that cluster the catalog never names it, and the read falls back to the agent's default cluster, safe because a materialized view serves from storage without one. Each product also reports whether its dataflow is caught up, so the agent can confirm it is reading a complete, current answer before it queries.
Several data products, linked by their shared keys, are a context graph: a live model of the business the agent reads and acts through. Materialize maintains the whole graph incrementally, so every object stays consistent with the others at a single point in time. An agent never joins a customer to an order that was already cancelled, or reads inventory a pending order has already reserved. It observes the result of its last action and acts again, on a picture that is current and internally consistent every time it looks.
What the developer server answers
Once connected, you ask the developer server about your environment in plain language and let it work out the query:
Where the agent server exposes your data products, the developer server exposes two tools. `query_system_catalog` runs one read-only statement like SELECT, SHOW, or EXPLAIN against the system catalog and rejects anything that writes. `query` is a broader read-only tool that takes an explicit cluster and can reach user objects too, which is what enables `EXPLAIN ANALYZE MEMORY` on a specific cluster. The assistant turns your question into a query, runs it through the right tool, and reads back the result.
It draws on the same catalog tables you would reach for by hand. And the default privileges already let a role read the system catalog, so there is nothing extra to grant for basic use.
Every permission check happens in the SQL adapter. A tool call runs through the same execution path as a statement sent to Materialize's SQL API, against the role the session connected as, so it inherits timestamp selection, strict serializability, and RBAC unchanged, and the same statement run by the same role returns the same error whether the request comes over MCP or over psql. If your support role lacks USAGE on a customer schema, SHOW CREATE VIEW fails the same way from both.
Connecting a client
The recommended path on Cloud is OAuth sign-in. Your MCP client opens a browser, you sign in through your normal SSO, and the client connects. Add the agent server to Claude Code with:
1 | |
2 | |
Swap /api/mcp/agent for /api/mcp/developer to connect the developer server instead. Claude Desktop and Cursor take the same URL in their JSON config.
For a service account, or a client that only supports token-based auth, MCP also accepts an Authorization: Basic header with a Base64-encoded user:password. That encoded string is your MCP token. On Cloud, open the Console, click Connect, and on the MCP Server tab generate a personal MCP token, which is a personal app password. If you already have an app password, you can encode it yourself:
1 | |
Then add the server you want to your client. For Claude Code, pointing at the agent server:
1 | |
2 | |
3 | |
Claude Desktop and Cursor take the same URL and header in their JSON config, and any HTTP client works with a plain POST:
1 | |
2 | |
3 | |
4 | |
Self-managed and the Emulator
The same servers ship everywhere Materialize runs. On Self-Managed you create a login role and encode its credentials:
1 | |
1 | |
Your base URL depends on the deployment shape. With SSO enabled, MCP is served at the same domain as your Materialize Console: https://<your-console-domain>/api/mcp/agent or /api/mcp/developer. For a direct-to-environmentd setup, use the deployment's HTTP endpoint. If you installed with the Terraform modules, Terraform can print it:
1 | |
Then connect to http://<host>:6876/api/mcp/agent or /api/mcp/developer. For a local kind cluster you port-forward 6876 and use localhost. The emulator works the same way with the default `materialize` user.
Get started
An agent's success comes down to the picture it reasons from, and that picture has to reflect what is true right now, increasingly so as you hand it more real work. Materialize keeps it live and correct as your business changes, and serving it from the database itself puts an agent one call away from the live state of your business, whether it is building on your data or operating the platform underneath it.
