> ## Documentation Index
> Fetch the complete documentation index at: https://docs.langchain.com/llms.txt
> Use this file to discover all available pages before exploring further.

# Add custom middleware to Managed Deep Agents

> Add built-in or custom middleware to Managed Deep Agents projects.

Managed Deep Agents support the normal Deep Agents `middleware` configuration surface. Add LangChain middleware to `define_deep_agent` or `defineDeepAgent` to monitor tool calls, add guardrails, redact data, retry transient failures, or customize model calls.

<Note>
  Managed Deep Agents is in **private [beta](/langsmith/release-stages)**, available on [LangSmith Cloud](/langsmith/cloud) in the US region only. [Join the waitlist](https://www.langchain.com/langsmith-managed-deep-agents-waitlist) to request access.
</Note>

The managed runtime still owns `backend`, `store`, `checkpointer`, `memory`, `skills`, and the system prompt. Middleware should focus on agent behavior around model calls, tool calls, and lifecycle hooks.

For deeper hook, state, and context details, see [Custom middleware](/oss/python/langchain/middleware/custom).

## Add a middleware module

Put middleware code under `middleware/` in your project and import it from the agent entry. For the full project layout, see the [CLI project file reference](/langsmith/managed-deep-agents-cli#project-file-reference).

<CodeGroup>
  ```python middleware/audit.py theme={"theme":{"light":"catppuccin-latte","dark":"catppuccin-mocha"}}
  from collections.abc import Callable

  from langchain.agents.middleware import wrap_tool_call
  from langchain.messages import ToolMessage
  from langchain.tools.tool_node import ToolCallRequest
  from langgraph.types import Command


  @wrap_tool_call
  def log_tool_calls(
      request: ToolCallRequest,
      handler: Callable[[ToolCallRequest], ToolMessage | Command],
  ) -> ToolMessage | Command:
      print(f"Calling tool: {request.tool_call['name']}")
      result = handler(request)
      print(f"Finished tool: {request.tool_call['name']}")
      return result
  ```

  ```ts middleware/audit.ts theme={"theme":{"light":"catppuccin-latte","dark":"catppuccin-mocha"}}
  import { createMiddleware } from "langchain";

  export const logToolCalls = createMiddleware({
    name: "LogToolCalls",
    wrapToolCall: async (request, handler) => {
      console.log(`Calling tool: ${request.toolCall.name}`);
      const result = await handler(request);
      console.log(`Finished tool: ${request.toolCall.name}`);
      return result;
    },
  });
  ```
</CodeGroup>

## Attach middleware to the agent

Import the middleware into the project-root agent entry and pass it in the `middleware` list.

<CodeGroup>
  ```python agent.py theme={"theme":{"light":"catppuccin-latte","dark":"catppuccin-mocha"}}
  from managed_deepagents import define_deep_agent

  from middleware.audit import log_tool_calls

  agent = define_deep_agent(
      model="openai:gpt-5.5",
      middleware=[log_tool_calls],
  )
  ```

  ```ts agent.ts theme={"theme":{"light":"catppuccin-latte","dark":"catppuccin-mocha"}}
  import { defineDeepAgent } from "managed-deepagents";

  import { logToolCalls } from "./middleware/audit";

  export const agent = defineDeepAgent({
    model: "openai:gpt-5.5",
    middleware: [logToolCalls],
  });
  ```
</CodeGroup>

`mda dev` and `mda deploy` copy the project files into the compiled build. Your middleware imports should work the same way they do in a normal local Python or TypeScript project.

## Use prebuilt middleware

You can also pass LangChain prebuilt middleware directly in the agent definition.

<CodeGroup>
  ```python agent.py theme={"theme":{"light":"catppuccin-latte","dark":"catppuccin-mocha"}}
  from langchain.agents.middleware import ModelCallLimitMiddleware, PIIMiddleware
  from managed_deepagents import define_deep_agent

  agent = define_deep_agent(
      model="openai:gpt-5.5",
      middleware=[
          PIIMiddleware("email", strategy="redact", apply_to_input=True),
          ModelCallLimitMiddleware(run_limit=50),
      ],
  )
  ```

  ```ts agent.ts theme={"theme":{"light":"catppuccin-latte","dark":"catppuccin-mocha"}}
  import { defineDeepAgent } from "managed-deepagents";
  import { modelCallLimitMiddleware, piiMiddleware } from "langchain";

  export const agent = defineDeepAgent({
    model: "openai:gpt-5.5",
    middleware: [
      piiMiddleware("email", { strategy: "redact", applyToInput: true }),
      modelCallLimitMiddleware({ runLimit: 50 }),
    ],
  });
  ```
</CodeGroup>

Middleware is the right place for cross-cutting behavior such as PII handling, rate limits, retry policies, model fallbacks, dynamic model selection, and tool-call monitoring.

## Human-in-the-loop

Pause the agent before sensitive tool calls so a person can approve, edit, or reject them. Set `interrupt_on` (Python) or `interruptOn` (TypeScript) in the agent definition, and optionally set `permissions` to gate tool and filesystem access.

<CodeGroup>
  ```python agent.py theme={"theme":{"light":"catppuccin-latte","dark":"catppuccin-mocha"}}
  from managed_deepagents import define_deep_agent

  from tools.customer import lookup_customer

  agent = define_deep_agent(
      model="openai:gpt-5.5",
      tools=[lookup_customer],
      interrupt_on={"lookup_customer": True},
  )
  ```

  ```ts agent.ts theme={"theme":{"light":"catppuccin-latte","dark":"catppuccin-mocha"}}
  import { defineDeepAgent } from "managed-deepagents";

  import { lookupCustomer } from "./tools/customer";

  export const agent = defineDeepAgent({
    model: "openai:gpt-5.5",
    tools: [lookupCustomer],
    interruptOn: {
      lookup_customer: true,
    },
  });
  ```
</CodeGroup>

The `interrupt_on` field applies the same interrupt behavior as LangChain's [human-in-the-loop middleware](/oss/python/langchain/guardrails#human-in-the-loop). For decision types (approve, edit, reject), conditional interrupts, and permission rules, see the Deep Agents [Human-in-the-loop](/oss/python/deepagents/human-in-the-loop) and [Permissions](/oss/python/deepagents/permissions) guides.

### Respond to an interrupt

When a run hits an interrupt, it pauses and waits for a human response before continuing.

* **During local development**, `mda dev` runs the agent in LangSmith Studio, which surfaces the interrupt so you can inspect the pending tool call and resume the run.
* **On a deployed agent**, resume the paused run through the LangGraph server API with a `Command(resume=...)` payload. See [Human-in-the-loop using server API](/langsmith/add-human-in-the-loop).

<Note>
  During private beta, Managed Deep Agents is CLI-first and programmatic invocation is not yet documented. To resume runs programmatically from your own application, contact your LangChain team.
</Note>

Human-in-the-loop needs durable thread state to pause and resume. The managed runtime owns the checkpointer, so no extra setup is required. For how threads persist, see [How Managed Deep Agents work](/langsmith/managed-deep-agents-how-it-works#threads-and-memory).

## Use runtime context

Middleware can read per-run context through the normal LangChain runtime APIs. Use context for user IDs, tenant IDs, feature flags, request metadata, or credentials that should not be part of the model prompt by default.

For examples, see [Custom middleware](/oss/python/langchain/middleware/custom).

## Test and deploy

Test the project locally with [`mda dev`](/langsmith/managed-deep-agents-cli#develop-locally), then deploy it with [`mda deploy`](/langsmith/managed-deep-agents-deploy). Open deployment traces in LangSmith to inspect model calls, tool calls, errors, and latency.

***

<div className="source-links">
  <Callout icon="terminal-2">
    [Connect these docs](/use-these-docs) to Claude, VSCode, and more via MCP for real-time answers.
  </Callout>

  <Callout icon="edit">
    [Edit this page on GitHub](https://github.com/langchain-ai/docs/edit/main/src/langsmith/managed-deep-agents-middleware.mdx) or [file an issue](https://github.com/langchain-ai/docs/issues/new/choose).
  </Callout>
</div>
