From 1009b891d4b37b3fc091adede8384599317cdf82 Mon Sep 17 00:00:00 2001 From: Monty Lennie Date: Wed, 15 Jul 2026 12:25:24 -0600 Subject: [PATCH 1/3] docs(publishing): match the MCP page to the shipped server Publisher consolidated its MCP surface onto a single endpoint in malloydata/publisher#884, and this page was never updated. Following it today points an agent at a port that is not listening, and at four tools that no longer exist. Verified against the published @malloy-publisher/server@0.0.227 over MCP rather than against the source tree: - The second agent server on :4041 (AGENT_MCP_PORT) is gone. Nothing listens there, and the setting appears nowhere in the codebase. Everything is served from :4040, so the separate "Agent Retrieval Tools and Skills" section folds into MCP Tools. - malloy_projectList, malloy_packageList, malloy_packageGet, and malloy_modelGetText were removed. tools/call returns "Tool not found", and they did not move to resources: resources/list is empty. Progressive malloy_getContext replaced them, so Discovery documents that instead. - The parameter is environmentName, not projectName. - The bridge download 404s: #884 deleted packages/server/dxt/malloy_bridge.py. The bridge still ships inside packages/server/malloy_mcp.dxt and still targets :4040, so the section points there and shows how to unpack it. Two parameter contracts are documented the way the server actually enforces them, since both fail in ways a reader would not predict: - malloy_executeQuery needs sourceName alongside queryName. Running a view with queryName alone fails with "Reference to undefined object"; the server's own constant says "Either 'query' or both 'sourceName' and 'queryName' must be provided". - malloy_getContext ignores packageName unless environmentName is set, and returns the environment list rather than an error, so the discovery steps are documented as needing the ones before them. One thing the page never said, verified against the shipped server rather than assumed: - The endpoint is unauthenticated and Publisher binds 0.0.0.0 by default (server.ts:160), which the MCP listener uses (server.ts:1859), so the npx command at the top of this page exposes malloy_executeQuery on every interface rather than loopback. Publisher's own AGENTS.md and docs/ai-agents.md both carry this warning; the public page did not. The wording here is taken from docs/ai-agents.md rather than invented. Worth a separate issue: publisher's --help (server.ts:105) claims the default is localhost, which is wrong, and is plausibly how the localhost framing reached these docs. This documents only what 0.0.227 serves. malloy_compile and malloy_reloadPackage are on publisher main but not in a release yet, so they are left for the release that carries them. Signed-off-by: Monty Lennie --- .../publishing/mcp_agents.malloynb | 54 ++++++++----------- 1 file changed, 23 insertions(+), 31 deletions(-) diff --git a/src/documentation/user_guides/publishing/mcp_agents.malloynb b/src/documentation/user_guides/publishing/mcp_agents.malloynb index 89461120..ea0bec88 100644 --- a/src/documentation/user_guides/publishing/mcp_agents.malloynb +++ b/src/documentation/user_guides/publishing/mcp_agents.malloynb @@ -17,6 +17,8 @@ npx @malloy-publisher/server --server_root /path/to/your/packages The AI sees all packages under your `server_root` directory. The MCP server starts automatically at `http://localhost:4040/mcp`. +The endpoint does not require authentication, and Publisher binds `0.0.0.0` by default, so anyone who can reach port 4040 on your network can run `malloy_executeQuery` against the databases your models connect to. Bind it to loopback with `--host 127.0.0.1` for local-only use, and put an authenticating gateway in front before exposing it more widely. + For other deployment options (Docker, git clone), see [Publish Your Models](publishing.malloynb). ### 2. Configure Your MCP Client @@ -49,11 +51,15 @@ Some MCP clients (VS Code, Claude Desktop) require stdio-based commands instead - Python 3.x installed - Malloy Publisher MCP Server running on `localhost:4040/mcp` -### 1. Download the Bridge +### 1. Get the Bridge + +The bridge ships inside [malloy_mcp.dxt](https://github.com/malloydata/publisher/blob/main/packages/server/malloy_mcp.dxt), a Desktop Extension bundle. Hosts that install `.dxt` extensions directly (such as Claude Desktop) can use that file as-is. -[Download malloy_bridge.py](https://github.com/malloydata/publisher/blob/main/packages/server/dxt/malloy_bridge.py) +For any other host, the bundle is a zip: unpack it and save `malloy_bridge.py` somewhere accessible, for example `~/malloy_bridge.py`. -Save it somewhere accessible, for example: `~/malloy_bridge.py` +```bash +unzip malloy_mcp.dxt malloy_bridge.py -d ~/ +``` ### 2. Configure Your MCP Client @@ -88,51 +94,37 @@ Check `/tmp/malloy_bridge.log` for debugging information. ## MCP Tools -Publisher exposes these tools to AI agents: +Publisher serves these tools from the single MCP endpoint, alongside the bundled agent skills as prompts. ### Discovery -| Tool | Parameters | Description | -|------|------------|-------------| -| `malloy_projectList` | — | List all available projects | -| `malloy_packageList` | `projectName` | List packages in a project | -| `malloy_packageGet` | `projectName`, `packageName` | Get models in a package | -| `malloy_modelGetText` | `projectName`, `packageName`, `modelPath` | Get raw model source code | - -### Query Execution +`malloy_getContext` is the entry point. Every parameter is optional, so an agent can start with nothing and narrow down as it learns the names. | Tool | Parameters | Description | |------|------------|-------------| -| `malloy_executeQuery` | `projectName`, `packageName`, `modelPath`, `query` | Run a Malloy query, returns JSON results | +| `malloy_getContext` | all optional: `environmentName`, `packageName`, `query`, `sourceName`, `limit` | Progressively discover what is on the server, and the model entities most relevant to a plain-English question. | ---- +Call it with no arguments to list the environments and the packages in each, with an `environmentName` to list that environment's packages, with `environmentName` plus `packageName` to list that package's sources, and with `environmentName` plus `packageName` plus a plain-English `query` to get the sources, views, named queries, and dimension/measure fields most relevant to it, each with its model path and `#(doc)` description. Add `sourceName` alongside a `query` to focus retrieval on a single source. -## Agent Retrieval Tools and Skills +Each step needs the ones before it: `packageName` without `environmentName` is ignored, and you get the environment list back rather than an error. -Alongside the core MCP server on `:4040`, Publisher runs a second MCP server for agents on `:4041` (set by `AGENT_MCP_PORT`). It serves two read-only retrieval tools plus the bundled agent skills, configured the same way as the core server but on the agent endpoint: +The `environmentName`, `packageName`, and `modelPath` it returns map directly onto `malloy_executeQuery`, so an agent can go from a question to a grounded query without guessing names. -```json -{ - "mcpServers": { - "malloy-publisher-agent": { - "url": "http://localhost:4041/mcp" - } - } -} -``` - -### Retrieval tools +### Query Execution | Tool | Parameters | Description | |------|------------|-------------| -| `malloy_getContext` | `environmentName`, `packageName`, `query`, `sourceName` (optional), `limit` (optional) | Given a plain-English question, returns the model entities (sources, views, named queries, and dimension/measure fields) most relevant to it, each with its model path and `#(doc)` description. | -| `malloy_searchDocs` | `query`, `limit` (optional) | Keyword search over a bundled index of the Malloy documentation, returning matching pages with a short excerpt and a link. | +| `malloy_executeQuery` | required: `environmentName`, `packageName`, `modelPath`, and then either `query` or `queryName` plus `sourceName`. Optional: `filterParams`, `givens` | Run a Malloy query: ad hoc with `query`, or a named query or view with `queryName` plus the `sourceName` it belongs to. Exactly one of `query` and `queryName` is required. Returns JSON results. | + +### Documentation Search -Use `malloy_getContext` in two phases: call it once with just a `query` to discover the most relevant sources and views, then optionally call it again with `sourceName` set to focus on the fields within one source. The `environmentName`, `packageName`, and `modelPath` it returns map directly onto `malloy_executeQuery`, so an agent can go from a question to a grounded query without guessing field names. +| Tool | Parameters | Description | +|------|------------|-------------| +| `malloy_searchDocs` | required: `query`. Optional: `limit` | Keyword search over a bundled index of the Malloy documentation, returning matching pages with a short excerpt and a link. | ### Skills as MCP prompts -Publisher also ships a set of agent **skills**: short guides that teach an agent how to write Malloy, choose charts, and verify results. Skill-aware hosts (such as Claude Code and Claude Desktop) load the skill files directly. For hosts that only ingest MCP, the agent server also exposes each skill as an MCP prompt, so the same guidance is available either way: list them with `prompts/list` on the agent endpoint and fetch one with `prompts/get`. +Publisher also ships a set of agent **skills**: short guides that teach an agent how to write Malloy, choose charts, and verify results. Skill-aware hosts (such as Claude Code and Claude Desktop) load the skill files directly. For hosts that only ingest MCP, the server also exposes each skill as an MCP prompt, so the same guidance is available either way: list them with `prompts/list` and fetch one with `prompts/get`. ## Example Prompts From b4bbf2b414fbb1ccda06937cd565ad8e13f02afd Mon Sep 17 00:00:00 2001 From: Monty Lennie Date: Mon, 20 Jul 2026 15:17:19 -0600 Subject: [PATCH 2/3] docs(publishing): document malloy_compile and malloy_reloadPackage The page listed three tools; the shipped server serves five. The two missing ones close the edit-and-run loop, which is the thing an agent most needs and the reason the page exists. They were left out on purpose when this branch was written, because the then current release predated them. That stopped being true when 0.0.228 shipped, so the page would have landed already incomplete. States plainly that compiling before reloading is a speed-up rather than a safety measure: a failed reload keeps serving the previously compiled model. Signed-off-by: Monty Lennie --- .../user_guides/publishing/mcp_agents.malloynb | 17 ++++++++++++++++- 1 file changed, 16 insertions(+), 1 deletion(-) diff --git a/src/documentation/user_guides/publishing/mcp_agents.malloynb b/src/documentation/user_guides/publishing/mcp_agents.malloynb index ea0bec88..81aa088a 100644 --- a/src/documentation/user_guides/publishing/mcp_agents.malloynb +++ b/src/documentation/user_guides/publishing/mcp_agents.malloynb @@ -17,7 +17,7 @@ npx @malloy-publisher/server --server_root /path/to/your/packages The AI sees all packages under your `server_root` directory. The MCP server starts automatically at `http://localhost:4040/mcp`. -The endpoint does not require authentication, and Publisher binds `0.0.0.0` by default, so anyone who can reach port 4040 on your network can run `malloy_executeQuery` against the databases your models connect to. Bind it to loopback with `--host 127.0.0.1` for local-only use, and put an authenticating gateway in front before exposing it more widely. +The endpoint does not require authentication, and Publisher binds `0.0.0.0` by default, so anyone who can reach port 4040 on your network can run `malloy_executeQuery` against the databases your models connect to. The surface is not read-only either: `malloy_reloadPackage` mutates server state, and for a package that carries an install location a reload re-fetches it, overwriting on-disk edits. The same effects are already reachable through the equivalent REST endpoints, so this is a reason to gate the deployment rather than a reason to avoid the tools. Bind it to loopback with `--host 127.0.0.1` for local-only use, and put an authenticating gateway in front before exposing it more widely. For other deployment options (Docker, git clone), see [Publish Your Models](publishing.malloynb). @@ -116,6 +116,21 @@ The `environmentName`, `packageName`, and `modelPath` it returns map directly on |------|------------|-------------| | `malloy_executeQuery` | required: `environmentName`, `packageName`, `modelPath`, and then either `query` or `queryName` plus `sourceName`. Optional: `filterParams`, `givens` | Run a Malloy query: ad hoc with `query`, or a named query or view with `queryName` plus the `sourceName` it belongs to. Exactly one of `query` and `queryName` is required. Returns JSON results. | +### Authoring + +These two close the edit-and-run loop, so an agent can change a model and query the result without restarting the server. + +| Tool | Parameters | Description | +|------|------------|-------------| +| `malloy_compile` | required: `environmentName`, `packageName`, `modelPath`, `source`. Optional: `includeSql`, `givens` | Compile-check Malloy source against a model and get structured diagnostics back, without running a query. The source is appended to `modelPath`, so that model's imports, sources, and queries are in scope. | +| `malloy_reloadPackage` | required: `environmentName`, `packageName` | Recompile a package from its on-disk model files, so a source or view added after boot becomes resolvable by name. Returns the mode it used, `in-place` or `reinstalled`. | + +Publisher compiles each configured package at boot and serves that cached model, so a source you add afterwards is not queryable by name until the package is reloaded. `malloy_compile` does not need a reload: it validates against the model as it is on disk. + +Compiling before reloading is a speed-up, not a safety measure. A reload that fails to compile leaves your files alone and keeps serving the previously compiled model, returning the compile errors, so nothing breaks either way. `malloy_compile` is simply the faster way to see diagnostics. + +One caveat worth knowing: a package whose stored metadata carries an install location is re-fetched from that source on reload, which overwrites on-disk edits. Check the returned mode if you had edits you did not save elsewhere. + ### Documentation Search | Tool | Parameters | Description | From 7db16478c40c7bffd060147b2a467a52b89ca81e Mon Sep 17 00:00:00 2001 From: Monty Lennie Date: Wed, 22 Jul 2026 09:54:28 -0600 Subject: [PATCH 3/3] docs(publishing): replace the removed stdio bridge with mcp-remote Publisher #884 deleted the DXT bridge (malloy_bridge.py and its manifest), and mcp-remote is the stdio path now. The malloy_mcp.dxt bundle still in the repo is a dead leftover the cleanup missed, so the section pointed readers at a file that no longer works. Replaces it with the mcp-remote config publisher's own AGENTS.md and docs/ai-agents.md recommend. Drops VS Code from the heading: it connects straight to the HTTP endpoint, so it belongs in the Quick Start, not here. Signed-off-by: Monty Lennie --- .../publishing/mcp_agents.malloynb | 45 +++---------------- 1 file changed, 7 insertions(+), 38 deletions(-) diff --git a/src/documentation/user_guides/publishing/mcp_agents.malloynb b/src/documentation/user_guides/publishing/mcp_agents.malloynb index 81aa088a..d8bce087 100644 --- a/src/documentation/user_guides/publishing/mcp_agents.malloynb +++ b/src/documentation/user_guides/publishing/mcp_agents.malloynb @@ -42,53 +42,22 @@ Once connected, try prompts like: --- -## Stdio Bridge (VS Code, Claude Desktop, etc.) +## Stdio-only Clients (older Claude Desktop, etc.) -Some MCP clients (VS Code, Claude Desktop) require stdio-based commands instead of HTTP. Use the bridge script to translate between protocols. - -### Prerequisites - -- Python 3.x installed -- Malloy Publisher MCP Server running on `localhost:4040/mcp` - -### 1. Get the Bridge - -The bridge ships inside [malloy_mcp.dxt](https://github.com/malloydata/publisher/blob/main/packages/server/malloy_mcp.dxt), a Desktop Extension bundle. Hosts that install `.dxt` extensions directly (such as Claude Desktop) can use that file as-is. - -For any other host, the bundle is a zip: unpack it and save `malloy_bridge.py` somewhere accessible, for example `~/malloy_bridge.py`. - -```bash -unzip malloy_mcp.dxt malloy_bridge.py -d ~/ -``` - -### 2. Configure Your MCP Client - -Example configuration for VS Code (`settings.json` or `.vscode/mcp.json`): +Some MCP clients speak only stdio, not HTTP. Bridge them to the HTTP endpoint with [`mcp-remote`](https://www.npmjs.com/package/mcp-remote), which needs no extra script. In the client's MCP config add: ```json { - "mcp": { - "servers": { - "malloy": { - "command": "python3", - "args": ["/full/path/to/malloy_bridge.py"] - } + "mcpServers": { + "malloy": { + "command": "npx", + "args": ["-y", "mcp-remote", "http://localhost:4040/mcp", "--allow-http"] } } } ``` -Replace `/full/path/to/malloy_bridge.py` with the actual path where you saved the bridge script. - -### Testing the Bridge - -Test the bridge script: - -```bash -echo '{"jsonrpc":"2.0","method":"tools/list","id":1}' | python3 /path/to/malloy_bridge.py -``` - -Check `/tmp/malloy_bridge.log` for debugging information. +`--allow-http` is required because the endpoint is plain HTTP on localhost. For Claude Desktop the config lives under Settings > Developer > Edit Config. ---