MDK Logo

Expose data to the agent

Turn an app's HTTP routes into MCP tools the operator agent can call, with no separate MCP manifest

Overview

The operator agent calls fleet data and actions as MCP tools. An app's routes become those tools with no separate MCP manifest to author and keep in sync: the standalone MCP server reads the app's own mdk-plugin.json route table — the same file the Gateway reads — and converts each route into a tool.

The MCP server is its own process. The Gateway hosts no MCP code and needs no MCP configuration. Neither runs app code: both read the app's route table and forward each call to the app's runtime, so the app runs once, in its own process.

This page shows the mdk.yaml shape that wires this up, the same way declaring an app does. It's an addition to your own site config, not a fixture to boot as written: the Kernel, Gateway, and apps are whatever your site already has. Nothing MCP-related goes in your startGateway() call — the standalone mdk run mcp process reads the same spec.apps list the Gateway serves.

Prerequisites

  • An app declared in spec.apps
  • The stack is running — mdk run starts the Kernel and the app runtimes the MCP server forwards to. Kernel's caller allowlist governs whether the MCP server's connection to the Kernel is admitted

Serve an app's routes as tools

Nothing is added to the app. Declare it in mdk.yaml as usual and start the MCP server:

spec:
  gateway:
    port: 3000
  apps:
    - name: custom-metrics
      package: ./apps/custom-metrics
  mcp:
    port: 3100   # optional — defaults to gateway.port + 100
mdk run          # first, in its own terminal
mdk run mcp      # then, in another

mdk run mcp reads the same spec.apps list the Gateway serves, so an app's routes are reachable over HTTP and over MCP without being declared twice. Each route becomes a tool named after its id (dots and other non-alphanumeric characters become underscores), with the description, safety hint, and input schema derived from the route's http block. Path, query, and header parameters and the requestBody's top-level properties become the tool's input fields. A tool call reaches the same controller, in the same app runtime, as an HTTP request to the route, with spec.mcp.identity as the caller. Until mdk run has started the app, its tools return ERR_APP_RUNTIME_UNAVAILABLE.

Only routes marked "safety": "read-only" become tools by default. Every other route is withheld as a write unless the server is started with --allow-write (or spec.mcp.allowWrite), or the tool is named in spec.mcp.allowTools.

mcp is never part of the default all target; it is always started explicitly.

Write tools by hand instead

An app that needs a different tool granularity, richer descriptions, or direct mdkClient calls can author an mcp-plugin.json by hand. A standalone MCP server serves both kinds at once — hand-authored tool plugins alongside app-derived ones — so a curated tool set and auto-derived routes can live on one endpoint. Tool ids must be unique across both sources; a collision is a startup error, not a silent override.

Serving hand-authored tools this way means embedding the standalone server through createMcpServer(), as the @tetherto/mdk-mcp README shows. mdk run mcp reads no spec.mcp.plugins list yet, so from mdk.yaml alone it serves only the app-derived tools above.

Next steps

On this page