Skip to main content
Managed agents can define Python tools directly in their versioned configuration. Put each tool in tools with an explicit JSON Schema and embedded source. The source runs in Monty, with JSON arguments and a host-provided HTTP interface. New to managed agents? Follow the Managed Agents quickstart to test a function, save the configuration, and start a conversation. This page is the reference for the function and HTTP interfaces.
The entrypoint defaults to the tool’s name. Set entrypoint: main to use a different function. The function must be async, accept one argument, and return JSON-serializable data. Each invocation starts with fresh script state.

Tool definition

The model sees the name, description, and schema. It supplies one JSON object; MeshAgent calls the async entrypoint with that object and returns its JSON result to the model. Return strings, numbers, booleans, None, lists, or dictionaries containing JSON-compatible values. Printing captures logs for the local test result; it does not replace the function’s return value. The deployed tool result contains the returned JSON value. The sandbox supports Python data processing and the injected HTTP interface. It does not provide a general CPython environment: do not assume requests, aiohttp, an SDK package, filesystem APIs, subprocesses, or arbitrary imports are available. json and the examples on this page are supported; test additional language or library features with the exact source using agent tools test.

Schemas

The schema is sent as a strict function-tool schema and validates arguments before execution. Every object, including nested objects, must set additionalProperties: false and list every property in required. Represent optional values with nullable types, such as type: [string, "null"]. Local $defs references and nested anyOf schemas are supported. Remote schema references and a root anyOf are rejected. Annotations in the Python source do not generate the schema. The accepted schema keywords are: Other keywords, including $schema, allOf, oneOf, minLength, and maxLength, are rejected by the current strict-schema validator.

HTTP and optional secrets

Use a direct URL for requests that do not need a configured connection:
http.request supports GET, POST, PUT, PATCH, DELETE, HEAD, and OPTIONS. Pass scalar query values in params, custom headers in headers, and either a JSON value in json or a string in body. The response exposes status, status_code, headers, text, json(), and raise_for_status(). HTTP error statuses are returned normally until raise_for_status() is called. Transport errors and invalid requests raise Python exceptions.

Request arguments

response.json() and response.raise_for_status() are synchronous methods after the awaited request. Response headers use lowercase names and omit set-cookie. The interface returns text and JSON; it does not expose streaming responses, binary uploads, multipart file uploads, or a Python HTTP client session. Connections without use_proxy_secret make ordinary HTTP requests. Connections with a secret use MeshAgent’s existing secret proxy, which checks permission and injects authorization. The managed agent’s run_as service account needs the secrets:proxy scope and the secret’s use_proxy permission. Neither secret values nor the runtime’s bearer token are supplied to the script. Secret-backed requests cannot override the authorization header, and a connection’s path must stay on its configured origin. Only configure trusted API destinations for secrets. Set run_as on the agent to the service account that will make deployed calls:
Use your actual service account email. The caller saving the agent needs run_service_as; the runtime identity also needs use_proxy_secrets on the secret’s owning service account, as well as use_proxy on the secret itself. See Service Account Secrets and the HTTP Secret Proxy for permission and secret setup. Host-controlled transport headers cannot be overridden. Direct requests do not follow redirects. Deployed tools can call public HTTP(S) destinations; private addresses are blocked. The runtime does not expose filesystem access, process execution, arbitrary Python packages, or environment variables.

Test the current source before deploying

Run the actual source in your agent YAML file:
This command uses the same Monty executor as managed agents. It does not save or deploy the spec and does not require tests or fixtures inside the file. Output is JSON containing result, captured logs, and HTTP request summaries. Invalid arguments, Python errors, and timeouts fail the command with a nonzero exit code. HTTP requests are live and can change data. Secret-backed local tests use your current CLI identity and its proxy permissions. They do not impersonate the deployed agent’s service account. Use --allow-private-http only when testing against a local development server. Managed agents use a dedicated Monty execution pool when deployed with the default Helm configuration. HTTP calls and secret-proxy credentials stay in the managed-agent host. Each active Python invocation reserves an interpreter until it completes, including time waiting on HTTP; idle agent connections do not reserve interpreters. The pool scales independently of managed agents. The Rust CLI container image includes Monty for local testing. For a local source checkout, install the pinned worker and, for the Python CLI, the shared runner:
Alternatively, set MESHAGENT_MONTY_BIN and MESHAGENT_PYTHON_TOOLS_BIN to the corresponding executables. The Rust CLI calls the shared runner directly and only needs the Monty executable.

Execution limits

Each invocation has a 30-second total deadline, a 10-second interpreter execution budget per feed, a 64 MiB sandbox memory limit, and at most 32 HTTP calls. Each request has a 15-second timeout. HTTP request data, response bodies, and returned JSON are limited to 1 MiB; captured logs are capped at 16 KiB. Source is limited to 64 KiB per tool.

Run the local managed-agent end-to-end suite

The dedicated suite exercises the real router, room tunnel, managed-agent runtime, Monty worker, and secret-proxy IAM. A recording HTTP service and a deterministic Responses provider run on the host. The provider supports both WebSockets and SSE and requests the exact function advertised by the agent. No external LLM is needed. From a source checkout, deploy the changed components to k3s-local:
Select a dedicated local test project and credentials that can manage its agents, settings, service accounts, secrets, and IAM. Configure the fixture URL with this host’s node InternalIP and an unused TCP port reachable from pods:
The runner sets RUN_MESHAGENT_CLOUD_SMOKE=1. It requires exactly one node in k3s-local, with this host’s name and instance type k3s, and refuses endpoints that resolve outside this host. It temporarily points the test project’s OpenAI settings at the fixture, creates separate secret-owner and agent service accounts, and adds an exact-origin HTTP exception and an exact-address/port network policy for the managed-agent pool. The roompool controller rolls out the configuration. The suite restores settings and pool configuration, removes the network policy, and deletes its agents, secrets, and service accounts on teardown. The eight live cases assert:
  • Saved source, schema, and connection round trips; real HTTP method, headers, query, body, and a fresh response nonce; parity with the CLI using the same YAML.
  • Secret injection, denial at both the secret use_proxy and service-account use_proxy_secrets gates, no upstream request on denial, and recovery after restoring permission. Secret values must not appear in provider traffic or client events.
  • Python exceptions, invalid arguments, missing functions, HTTP errors, and execution timeouts reaching the client as tool failures. Each case then runs a successful turn on the same agent connection.
  • An explicit entrypoint and updated source after terminating and restarting the agent session.
Run this suite serially against an otherwise idle local managed-agent pool. It changes that pool’s desired configuration temporarily; it does not connect to remote clusters. Normal teardown restores configuration, but a forcibly killed pytest process may require manual cleanup. The exact-origin host setting is MESHAGENT_PYTHON_HTTP_ALLOWED_ORIGINS (a JSON array), also exposed as Helm value meshagent.kubernetes.managedAgentsRoomPool.pythonHttpAllowedOrigins. Agent specs cannot grant this exception. Other private destinations remain blocked.

Dedicated execution pool

Helm settings under meshagent.monty control worker resources, session admission, gateway replicas, and autoscaling bounds. The chart configures the managed-agent host with MESHAGENT_MONTY_ENDPOINT, MESHAGENT_MONTY_TOKEN, and MESHAGENT_MONTY_MAX_CONNECTIONS. These are deployment settings, not agent YAML fields. Set meshagent.monty.enabled=false to retain local interpreter execution. Capacity exhaustion returns an error before execution. A lost worker or expired session fails the tool call without replaying it, since an HTTP request may already have taken effect. The execution pool drains active calls during shutdown. Run rust/meshagent-monty-service/run-tests.sh with MESHAGENT_MONTY_BIN set to a pinned 1.2.0 interpreter to validate the remote transport and the production HTTP host locally. ./local-build.sh --k3s --managed-agents builds the managed-agent and Monty service images and applies the Helm configuration.