Repository: knocklabs/docs
Pull request #842: feat: agent toolkit, mcp, and working with llms docs
Author: login: cjbell
Created: 2025-04-22T14:58:00Z | Merged: 2025-04-25T14:09:21Z

### Description

This PR adds new docs pages under the "Developer tools" section for:

- Agent toolkit
- MCP server
- Building with LLMs

### Tasks

KNO-8425

### Screenshots

<img width="1624" alt="image" src="https://github.com/user-attachments/assets/3949470a-b8ca-40d2-b184-c34170510a4e" />




Diff:
diff --git a/content/developer-tools/agent-toolkit/getting-started.mdx b/content/developer-tools/agent-toolkit/getting-started.mdx
new file mode 100644
index 000000000..2ba142963
--- /dev/null
+++ b/content/developer-tools/agent-toolkit/getting-started.mdx
@@ -0,0 +1,151 @@
+---
+title: Getting started with the Knock agent toolkit
+description: Learn how to use the Knock agent toolkit within your AI agent workflows to power cross-channel messaging and rich human-in-the-loop interactions.
+section: Developer tools
+---
+
+## Installing the Knock agent toolkit
+
+You can install the Knock agent toolkit using npm, yarn, or pnpm.
+
+```bash
+npm install @knocklabs/agent-toolkit
+```
+
+Once installed you can use the toolkit through the exposed SDK adapters, or if you need low-level access to the toolkit you can use the `@knocklabs/agent-toolkit` package directly.
+
+## Setting up your .env file
+
+You'll need to have a [service token](/developer-tools/service-tokens) setup on your Knock account to authenticate with the Knock Agent Toolkit.
+
+```bash
+KNOCK_SERVICE_TOKEN=st_1234567890
+```
+
+## Usage with the Vercel AI SDK
+
+```typescript title="Usage with the Vercel AI SDK"
+import { createToolkit } from "@knocklabs/agent-toolkit/ai-sdk";
+
+const toolkit = await createKnockToolkit({
+  serviceToken: process.env.KNOCK_SERVICE_TOKEN!,
+  permissions: {
+    users: { manage: true },
+  },
+});
+
+const result = await generateText({
+  model: openai("gpt-4o"),
+  tools: {
+    ...toolkit.getTools("users"),
+  },
+  maxSteps: 5,
+  prompt:
+    "Update the current user's profile with information about them, knowing that they are Alan Grant from Jurassic Park. Include custom properties about their favorite dinosaur.",
+});
+```
+
+## Usage with the OpenAI SDK
+
+```typescript title="Usage with the OpenAI SDK"
+import OpenAI from "openai";
+import { createToolkit } from "@knocklabs/agent-toolkit/openai";
+
+const toolkit = await createToolkit({
+  serviceToken: process.env.KNOCK_SERVICE_TOKEN!,
+});
+
+const openai = new OpenAI({
+  apiKey: process.env.OPENAI_API_KEY!,
+});
+
+const messages = [
+  {
+    role: "user",
+    content:
+      "Update the current user's profile with information about them, knowing that they are Alan Grant from Jurassic Park. Include custom properties about their favorite dinosaur.",
+  },
+];
+
+(async (): Promise<void> => {
+  const result = await openai.chat.completions.create({
+    model: "gpt-4o",
+    messages,
+  });
+
+  while (true) {
+    // eslint-disable-next-line no-await-in-loop
+    const completion = await openai.chat.completions.create({
+      model: "gpt-4o",
+      messages,
+      tools: toolkit.getTools("users"),
+    });
+
+    const message = completion.choices[0].message;
+
+    messages.push(message);
+
+    if (message.tool_calls) {
+      // eslint-disable-next-line no-await-in-loop
+      const toolMessages = await Promise.all(
+        message.tool_calls.map((tc) => toolkit.handleToolCall(tc)),
+      );
+      messages = [...messages, ...toolMessages];
+    } else {
+      console.log(completion.choices[0].message);
+      break;
+    }
+  }
+})();
+```
+
+## Usage with the LangChain framework
+
+```typescript title="Usage with the LangChain framework"
+import { createToolkit } from "@knocklabs/agent-toolkit/langchain";
+import { ChatOpenAI } from "@langchain/openai";
+import type { ChatPromptTemplate } from "@langchain/core/prompts";
+import { pull } from "langchain/hub";
+import { AgentExecutor, createStructuredChatAgent } from "langchain/agents";
+
+const toolkit = await createToolkit({
+  serviceToken: process.env.KNOCK_SERVICE_TOKEN!,
+});
+
+const llm = new ChatOpenAI({
+  model: "gpt-4o",
+});
+
+(async (): Promise<void> => {
+  const prompt = await pull<ChatPromptTemplate>(
+    "hwchase17/structured-chat-agent",
+  );
+
+  const tools = toolkit.getTools("users");
+
+  const agent = await createStructuredChatAgent({
+    llm,
+    tools,
+    prompt,
+  });
+
+  const agentExecutor = new AgentExecutor({
+    agent,
+    tools,
+  });
+
+  const response = await agentExecutor.invoke({
+    input:
+      "Update the user's profile with information about them, knowing that they are Alan Grant from Jurassic Park. Include custom properties about their favorite dinosaur.",
+  });
+
+  console.log(response);
+})();
+```
+
+## Related links
+
+- [Powering human-in-the-loop interactions](/developer-tools/agent-toolkit/human-in-the-loop-flows)
+- [Providing context](/developer-tools/agent-toolkit/providing-context)
+- [Building with LLMs](/developer-tools/building-with-llms)
+- [Model Context Protocol (MCP) Server](/developer-tools/mcp-server)
diff --git a/content/developer-tools/agent-toolkit/human-in-the-loop-flows.mdx b/content/developer-tools/agent-toolkit/human-in-the-loop-flows.mdx
new file mode 100644
index 000000000..2ecf76a3c
--- /dev/null
+++ b/content/developer-tools/agent-toolkit/human-in-the-loop-flows.mdx
@@ -0,0 +1,222 @@
+---
+title: Powering human-in-the-loop flows with the Knock agent toolkit
+description: Learn how to use the Knock agent toolkit within your AI agent workflows to power rich human-in-the-loop interactions.
+section: Developer tools
+---
+
+The Knock agent toolkit allows you to power rich human-in-the-loop interactions.
+
+For example, you can use the agent toolkit to create a workflow that lets a person to approve or reject work that the agent has done, powered by Knock's cross-channel messaging workflows.
+
+The agent toolkit exposes a set of helper methods that make it trivial for you to wrap your tool calls in asynchronous human approvals or inputs.
+
+Knock takes care of the heavy lifting for you, making it easy to build rich human-in-the-loop flows with little effort.
+
+## Use cases
+
+Using Knock, it's possible to power human-in-the-loop interactions that:
+
+- Send cross-channel notifications to email, SMS, in-app feeds, and workplace chat applications like Slack and MS Teams.
+- Power advanced cross-channel escalation flows to bubble up messages between channels or across team members.
+- Solicit structured input such as approve/reject buttons, or unstructured feedback in the form of text or prompt modifications.
+- Handle long-running async interactions that "interrupt" and "resume" your agent workflows.
+- Give full visibility into the messages sent from your AI agent workflows and track engagement of those messages across channels.
+
+## How Knock powers human-in-the-loop flows
+
+Knock uses [workflows](/concepts/workflows) to power human-in-the-loop messaging across channels. Here's a high-level overview of how this works:
+
+1. You setup a workflow in the Knock dashboard that describes the message to send and the channels to send it to.
+2. Your agent calls to Knock to [trigger the workflow](/send-notifications/triggering-workflows/overview) with a set of recipients and any additional context for the request.
+3. Your user receives the message on the channel, which includes the context for the request and a set of actions to take.
+4. The user then interacts with the message and the result is sent back to Knock.
+5. Knock then triggers an [outbound webhook](/developer-tools/outbound-webhooks/overview) back to your agent application with the result of the interaction.
+6. Your agent application can then use the incoming interaction event from Knock to resume execution, or respond to the interaction.
+
+## Helper methods
+
+<Callout
+  emoji="💡"
+  text={
+    <>
+      <strong>Note</strong>: The following helper methods are only exposed for
+      the AI SDK. If you're using the Knock agent toolkit with another agent
+      framework and need to implement a custom flow, please reach out to us at{" "}
+      <a href="mailto:support@knock.app">support@knock.app</a>.
+    </>
+  }
+/>
+
+The Knock agent toolkit exposes a set of helper methods that you can use to power human-in-the-loop flows for common cases, as well as low-level primitives should you need to implement a custom flow.
+
+### `toolkit.requiresHumanInput`
+
+The `requiresHumanInput` helper method allows you to wrap a tool in requiring human input to proceed. When a tool is wrapped with this method, when the LLM tries to invoke the call it will instead delegate the tool call to Knock, passing the tool execution context to the Knock workflow.
+
+```typescript title="Wrap tool in requiring input"
+import { createToolkit } from "@knocklabs/agent-toolkit/ai-sdk";
+
+const toolkit = await createToolkit({
+  serviceToken: process.env.KNOCK_SERVICE_TOKEN,
+});
+
+const { classifyWork: classifyToolRequiringInput } = toolkit.requireHumanInput(
+  { classifyWork },
+  {
+    // (required) The key of the workflow to trigger
+    workflow: "approve-classification",
+    // (required) The list of recipients to trigger the workflow for
+    recipients: ["user_123"],
+    // (optional) Any additional data to pass along with the request
+    data: {},
+  },
+);
+```
+
+Calling `requireHumanInput` will return a new tool that you pass in place of the original tool in your model. When the LLM invokes the new tool, it will instead delegate the tool call to Knock, passing the tool execution context to the Knock workflow.
+
+<Callout
+  emoji="🚧"
+  text={
+    <>
+      Note: when the LLM invokes the new tool, it will appear as if the
+      tool-call completed, albeit with a result that indicates that the tool is
+      still waiting for human input. This is expected behavior.
+    </>
+  }
+/>
+### `toolkit.handleMessageInteracted`
+
+The `handleMessageInteracted` helper method allows you to handle an incoming `message.interacted` event from Knock and determine if there's an interaction with the message that should be handled by your agent workflow.
+
+```typescript title="Handling an incoming interaction"
+import { createToolkit } from "@knocklabs/agent-toolkit/ai-sdk";
+
+const toolkit = await createToolkit({
+  serviceToken: process.env.KNOCK_SERVICE_TOKEN,
+});
+
+function handleIncomingInteraction(event) {
+  const interactionEvent = toolkit.handleMessageInteracted(event);
+
+  if (
+    interactionEvent &&
+    interactionEvent.workflow === "my-approval-workflow" &&
+    interactionEvent.interaction.action === "approved"
+  ) {
+    // Do something as a result of the approval
+  }
+}
+```
+
+### `toolkit.resumeToolExecution`
+
+The `resumeToolExecution` helper method allows you to resume tool execution after a human has interacted with the message and you have received an affirmative response to proceed.
+
+You pass the `resumeToolExecution` method the `DeferredToolCallInteractionResult` that you've received from Knock via the `handleMessageInteracted` method. Here's an example of how you might use this method:
+
+```typescript title="Resuming tool execution"
+import { createToolkit } from "@knocklabs/agent-toolkit/ai-sdk";
+
+const toolkit = await createToolkit({
+  serviceToken: process.env.KNOCK_SERVICE_TOKEN,
+});
+
+function handleIncomingInteraction(event) {
+  const interactionEvent = toolkit.handleMessageInteracted(event);
+
+  if (interactionEvent && interactionEvent.hasToolCall) {
+    const toolResult = await toolkit.resumeToolExecution(interactionEvent);
+    // Do something with the tool result
+  }
+}
+```
+
+When using the `resumeToolExecution` method, you must have first registered any tools that require human input using the `requiresHumanInput` method. This ensures that the toolkit has access to the necessary information to resume the tool execution.
+
+In the AI SDK, the `resumeToolExecution` method will return a tool status object where you can access the result under the `result` property. The original `toolCallId` is also included.
+
+## Example: In-app approval flow
+
+In this guide we show you how to setup an approval flow that sends an in-app notification to a notification feed requesting approval when the agent wishes to invoke a particular tool.
+
+<Steps>
+  <Step title="Setting up a workflow to power approvals">
+    To start, you'll want to setup a Knock workflow with a single, in-app feed channel step that sends an approval message to an in-app feed. You can find a workflow template for this in the [workflow templates repository](https://github.com/knocklabs/workflow-templates/tree/main/approve-tool-call).
+  </Step>
+  <Step title="Rendering the feed">
+    Next, you'll need to render the in-app feed in your application. You can find a guide on how to do this in the [building in-app feed guide](/in-app-ui/react/feed). By default, your in-app feed will handle the interaction on the "Approve" and "Reject" buttons and send the `message.interacted` event to Knock.
+  </Step>
+  <Step title="Setting up an outbound webhook in Knock">
+    A human-in-the-loop interaction is inherently an asynchronous action, and therefore requires that we might need to handle the approval at some later point. Knock uses [outbound webhooks](/developer-tools/outbound-webhooks/overview) to forward your events to your application, helping to implement this asynchronous behavior.
+
+    To set up an outbound webhook, you'll need to create a new webhook under **Developers** > **Webhooks** in the Knock dashboard. Add a URL for your service and select the `message.interacted` event. You can read more about the available [event types in our guide](/developer-tools/outbound-webhooks/event-types).
+
+  </Step>
+  <Step title="Wrapping a tool as requiring human input">
+    The agent toolkit exposes a `requiresHumanInput` helper that you can use to wrap a tool call as one that requires human input to proceed.
+ 
+    ```typescript title="Wrap a tool as requiring human input"
+    import { createToolkit } from "@knocklabs/agent-toolkit/ai-sdk";
+
+    const toolkit = await createToolkit({
+      serviceToken: process.env.KNOCK_SERVICE_TOKEN,
+    });
+
+    const { classificationTool: wrappedClassificationTool } = toolkit.requiresHumanInput({ classificationTool }, {
+      // The workflow to use to send the approval request
+      workflow: "approve-tool-call",
+      // A list of users who should be notified about this request
+      recipients: ["user_123", "user_456"],
+      data: {
+        // (optional) any additional data to send with the request that helps identify it
+        // this data will then be made available to you when receiving the webhook
+      }
+    });
+    ```
+
+    Now, when your agent calls your `classificationTool`, it will instead call your `wrappedClassificationTool` and delegate the tool call to Knock, bringing one or more humans into the agent's loop.
+
+  </Step>
+  <Step title="Handling the response and resuming tool execution">
+    Finally, you will need to implement a handler for the `message.interacted` webhook event that fires when someone interacts with the "approve" or "reject" buttons in the notification feed.
+
+    You'll use this method to handle the incoming interaction event and to resume your agent's execution. Depending on which agent framework you're using, you'll need to implement this handler differently. We've left this example fairly abstract as a result.
+
+    ```typescript title="Handling the response and resuming tool execution"
+    import { createToolkit, handleMessageInteracted } from "@knocklabs/agent-toolkit/ai-sdk";
+
+    const handleMessageInteracted = async (event: MessageInteractedEvent) => {
+      const agent = await getAgentInstance();
+
+      const toolkit = await createToolkit({
+        serviceToken: process.env.KNOCK_SERVICE_TOKEN,
+      });
+
+      const interactionEvent = toolkit.handleMessageInteracted(event);
+
+      if (interactionEvent && interactionEvent.interaction.action === "approved") {
+        const toolResult = await toolkit.resumeToolExecution(interactionEvent);
+        // Resume my agent's execution
+        await agent.resumeLoopWithToolResult(toolResult);
+      }
+    }
+    ```
+
+  </Step>
+</Steps>
+
+## Frequently asked questions
+
+<AccordionGroup>
+  <Accordion title="Can I power a direct approve/reject via email without routing the buttons through my server?">
+    No, right now you must setup a URL handler on your server to implement these
+    actions. One possible approach is that you drive the resulting approve or
+    reject click directly to your agent workflow to handle.
+  </Accordion>
+  <Accordion title="Can I power a direct approve/reject workflow via Slack or MS Teams without routing the interaction through my server?">
+    No, as with email you must implement a webhook handler for these channels
+    where you handle this interaction before sending it back to Knock to
+    proceed.
+  </Accordion>
+</AccordionGroup>
diff --git a/content/developer-tools/agent-toolkit/overview.mdx b/content/developer-tools/agent-toolkit/overview.mdx
new file mode 100644
index 000000000..36b414704
--- /dev/null
+++ b/content/developer-tools/agent-toolkit/overview.mdx
@@ -0,0 +1,96 @@
+---
+title: Agent toolkit
+description: Use Knock's agent toolkit to give your AI agents the ability to send cross-channel messaging and power rich human-in-the-loop flows.
+section: Developer tools
+---
+
+The Knock agent toolkit exposes a set of tools that your AI agent applications can use to interact with Knock via function calling. Using the Knock agent toolkit, you can:
+
+- Give your AI agent applications the ability to [send cross-channel notifications](/developer-tools/agent-toolkit/workflows-as-tools) to your users.
+- Power rich [human-in-the-loop flows](/developer-tools/agent-toolkit/human-in-the-loop-flows) that allow your agents to solicit structured input from users, or require human approval of actions taken by your agents.
+- Let your agents create and manage resources within your Knock account.
+
+<Callout
+  emoji="💡"
+  text={
+    <>
+      The Knock agent toolkit is currently in beta as a TypeScript package only.
+      We're considering adding support for Python too. If you're interested in
+      using the Knock agent toolkit in another language, please let us know at{" "}
+      <a href="mailto:support@knock.app">support@knock.app</a>.
+    </>
+  }
+/>
+
+## Workflows-as-tools
+
+By default the agent toolkit will expose each of your workflows as a tool that your agents can invoke to power cross-channel messaging. If you have a workflow (`comment-created`) within your Knock account, the agent toolkit will expose a `trigger_comment_created_workflow` tool that your agents can invoke to send a notification.
+
+Each tool describes the parameters that are required to trigger the workflow, where the parameters for the data payload are read from the [workflow's trigger data JSON schema](/developer-tools/validating-trigger-data). Adding the JSON schema for your workflow trigger data allows the LLM to understand the exact shape and definition of the data payload for the workflow.
+
+If the workflow does not specify a trigger data JSON schema, the tool will define a generic data payload for the AI agent to fill in.
+
+You can control this behavior by either:
+
+- Disabling entirely by setting `workflows.read` to `false`
+- Specifying a list of workflow keys that are allowed to be exposed to the agent (`workflows.read = ["comment-created"]`)
+
+Read more about [exposing workflows as tools](/developer-tools/agent-toolkit/workflows-as-tools).
+
+## Human-in-the-loop flows
+
+You can use the agent toolkit to power rich human-in-the-loop interactions.
+
+For example, you can use the agent toolkit to create a workflow that allows a person to approve or reject the agent's work, where the approval is an actionable notification sent by Knock.
+
+The toolkit exposes wrappers for requiring asynchronous human input. When wrapped, your tools will first delegate to Knock to trigger a workflow that you define, then asynchronously continue tool execution once you have received a response from a human.
+
+```typescript title="Wrapping a tool as requiring human input"
+import { createToolkit } from "@knocklabs/agent-toolkit/ai-sdk";
+
+const toolkit = createToolkit({
+  serviceToken: process.env.KNOCK_SERVICE_TOKEN,
+});
+
+const classifyToolRequiringInput = toolkit.requireHumanInput(classifyWork, {
+  workflow: "approve-classification",
+  recipients: ["user_123"],
+});
+```
+
+You can read more about [powering human-in-the-loop flows in the guide](/developer-tools/agent-toolkit/human-in-the-loop-flows).
+
+## Creating Knock resources
+
+You can create Knock resources using the agent toolkit through function calling.
+
+For example, you may want an agent to create or update a user's record in Knock as part of your agent workflow, or subscribe a user to another object so they can receive notifications later.
+
+The agent toolkit exposes most common Knock resources as tools that your agents can invoke.
+
+You can find the list of available tools in the [tools reference](/developer-tools/agent-toolkit/tools-reference).
+
+## Security and authorization
+
+To authenticate with the Knock agent toolkit, you need to provide a [service token](/developer-tools/service-tokens) for your Knock account. This token should be kept secret and not exposed to the LLM. Your service token grants access to all of your Knock resources, so it's important to keep it secure.
+
+You can also customize the tools exposed to the AI Agent by specifying a set of permissions that define the resources that the agent has access to.
+
+For example, the following permissions will expose only the `users` resource to the agent, which will include the ability to read and manage users.
+
+```typescript title="Setting permissions for the agent"
+{
+  permissions: {
+    users: {
+      read: true,
+      manage: true
+    },
+  },
+};
+```
+
+## Relevant links
+
+- [Getting started with the Knock agent toolkit](/developer-tools/agent-toolkit/getting-started)
+- [Building with LLMs](/developer-tools/building-with-llms)
+- [Model Context Protocol (MCP) Server](/developer-tools/mcp-server)
diff --git a/content/developer-tools/agent-toolkit/providing-context.mdx b/content/developer-tools/agent-toolkit/providing-context.mdx
new file mode 100644
index 000000000..7e1ac5b29
--- /dev/null
+++ b/content/developer-tools/agent-toolkit/providing-context.mdx
@@ -0,0 +1,34 @@
+---
+title: Providing context to your Knock agent toolkit instance
+description: Learn how to configure the Knock agent toolkit to use context to aid with tool calls in your AI agent workflows.
+section: Developer tools
+---
+
+The Knock agent toolkit allows you to pass context on initialization to automatically scope requests to Knock. This is useful when you're interacting with a single logged in user, or you already know the organization that the agent is interacting with.
+
+## Available context
+
+- `userId`: The user ID of the user that the agent is interacting with.
+- `tenantId`: The tenant ID of the organization/workspace/account that the agent is interacting with.
+
+## Setting context
+
+You can set context on the `createToolkit` method.
+
+```typescript
+const toolkit = await createToolkit({
+  serviceToken: process.env.KNOCK_SERVICE_TOKEN,
+  userId: "user_123",
+  tenantId: "tenant_123",
+});
+```
+
+## Where context is used
+
+Once you've set the `userId` or `tenantId` context, it will be used to automatically scope requests to Knock. This means that you don't need to pass the `userId` or `tenantId` with every request, it will be set automatically.
+
+Many of the tools that the Knock agent toolkit exposes will use the context as a default value, making it possible to omit the this parameter from the LLM's tool call.
+
+For example, when executing a workflow trigger where we have a `userId` set, we can say: `trigger the welcome workflow for the current user` instead of `trigger the welcome workflow for user_123`.
+
+Or, as another example when updating a user's profile, we can say: `update the profile for the current user` instead of `update the profile for user_123`.
diff --git a/content/developer-tools/agent-toolkit/tools-reference.mdx b/content/developer-tools/agent-toolkit/tools-reference.mdx
new file mode 100644
index 000000000..29241d9dd
--- /dev/null
+++ b/content/developer-tools/agent-toolkit/tools-reference.mdx
@@ -0,0 +1,85 @@
+---
+title: Tools reference
+description: Learn more about the tools available in the Knock agent toolkit.
+section: Developer tools
+---
+
+The Knock Agent Toolkit exposes a suite of tools that your AI Agents can invoke to power cross-channel user messaging, without any integration logic. You can find the full list of available tools below.
+
+## Channels
+
+- `listChannels`: List all channels in your Knock account
+
+## Commits
+
+- `listCommits`: List all commits in a single environment
+- `commitAllChanges`: Commit all changes in an enviroinment
+- `promoteAllCommits`: Promote all commits from one environment to another
+
+## Documentation
+
+- `searchDocumentation`: Perform a search of the Knock documentation
+
+## Email Layouts
+
+- `listEmailLayouts`: List all email layouts in an environment
+
+## Environments
+
+- `listEnvironments`: List all environments in your Knock account
+
+## Message types
+
+- `listMessageTypes`: List all message types in an environment
+- `createOrUpdateMessageType`: Create or update a message type in an environment
+
+## Messages
+
+- `getMessageContent`: Get the content of a sent message
+
+## Objects
+
+- `listObjects`: List all objects in a collection in an environment
+- `createOrUpdateObject`: Create or update an object in a collection
+- `getObject`: Get an object in a collection by its id
+- `subscribeUsersToObject`: Subscribe one or more users to an object in a collection
+- `unsubscribeUsersFromObject`: Unsubscribe one or more users from an object in a collection
+
+## Partials
+
+- `listPartials`: List all partials in an environment
+- `getPartial`: Get a partial by its key
+- `createOrUpdatePartial`: Create or update a partial in an environment
+
+## Tenants
+
+- `listTenants`: List all tenants in an environment
+- `setTenant`: Create or update a tenant in an environment
+- `getTenant`: Get a tenant by its key
+
+## Users
+
+- `listUsers`: List all users in an environment
+- `createOrUpdateUser`: Create or update a user in an environment
+- `getUser`: Get a user by their id
+- `getUserPreferences`: Get the preferences for a user
+- `setUserPreferences`: Set the preferences for a user
+- `getUserMessages`: Get the messages for a user
+
+## Workflows
+
+- `listWorkflows`: List all workflows in an environment
+- `getWorkflow`: Get a workflow by its key
+- `triggerWorkflow`: Trigger a workflow by its key
+- `createWorkflow`: Create a new workflow
+- `createOneOffWorkflowSchedule`: Create a one-off schedule for a user to trigger a workflow
+
+## Workflow steps
+
+- `createEmailStepInWorkflow`: Create an email step in a workflow
+- `createDelayStepInWorkflow`: Create a delay step in a workflow
+- `createBatchStepInWorkflow`: Create a batch step in a workflow
+- `createInAppFeedStepInWorkflow`: Create an in-app feed step in a workflow
+- `createPushStepInWorkflow`: Create a push notification step in a workflow
+- `createSmsStepInWorkflow`: Create an SMS step in a workflow
+- `createChatStepInWorkflow`: Create a chat step in a workflow
diff --git a/content/developer-tools/agent-toolkit/workflows-as-tools.mdx b/content/developer-tools/agent-toolkit/workflows-as-tools.mdx
new file mode 100644
index 000000000..3171fca1e
--- /dev/null
+++ b/content/developer-tools/agent-toolkit/workflows-as-tools.mdx
@@ -0,0 +1,76 @@
+---
+title: Workflows-as-tools
+description: Learn how the Agent Toolkit exposes your workflows as tools that your AI Agents can invoke to power cross-channel user messaging, without any integration logic.
+section: Developer tools
+---
+
+By default the agent toolkit will expose each of your workflows as a tool that your agents can invoke to power cross-channel messaging.
+
+If you have a workflow (`comment-created`) within your Knock account, the agent toolkit will expose a `trigger_comment_created_workflow` tool that your agents can invoke to send a notification.
+
+You can think of this as exposing a well-scoped API endpoint that describes exactly how the workflow should be triggered to the LLM/AI Agent. That makes it trivial to build agents that can trigger complex cross-channel messaging flows, with no integration logic.
+
+## Configuring which workflows are exposed as tools
+
+When using the agent toolkit, you can optionally configure exactly which workflows are exposed as tools. To do so, you can set the `permissions.workflows.run` property on the agent toolkit configuration.
+
+In the below example, we're ensuring that **only** the `comment-created`, `task-completed`, and `welcome-user` workflows are exposed as tools to the LLM:
+
+```typescript
+const toolkit = createAgentToolkit({
+  permissions: {
+    workflows: {
+      run: ["comment-created", "task-completed", "welcome-user"],
+    },
+  },
+});
+```
+
+If you wish to omit exposing any workflows as tools, you can set the `permissions.workflows.run` property to an empty array:
+
+```typescript
+const toolkit = createAgentToolkit({
+  permissions: { workflows: { run: [] } },
+});
+```
+
+## Describing the trigger data for each workflow
+
+The trigger data tool created for each workflow exposes the [workflow's trigger data JSON schema](/developer-tools/validating-trigger-data) to the LLM to describe the data payload required to trigger the workflow, and what the shape of that expected data should be.
+
+This allows you to define an explicit contract for your workflow and ensure that the LLM is passing in the correct data when invoking the workflow to send notifications, adding a safe guard so that workflows cannot be triggered with incorrect data supplied.
+
+## Tips for exposing workflows to LLMs
+
+<AccordionGroup>
+  <Accordion title="Use the workflow description to add additional calling context for the LLM">
+    The workflow description is a great place to add additional calling context
+    for the LLM as it is injected into the prompt that exposes the tool. That
+    means you can use the description to add additional calling context, like
+    when the workflow should be used, or what the context of the workflow is.
+  </Accordion>
+  <Accordion title="Limit the workflows that are exposed to the LLM">
+    It's best if you limit the workflows exposed to the LLM as tools to only
+    those that you absolutely know that the LLM can trigger. This helps keep the
+    LLM "focused" on the task, and sticks to best practice about the total
+    number of tools available.
+  </Accordion>
+  <Accordion title="Ensure your trigger data JSON schema has good descriptions">
+    The trigger data JSON schema is a great place to add descriptions to the
+    fields of the data payload. This helps the LLM understand the data payload
+    and fill it in accurately.
+  </Accordion>
+  <Accordion title="Keep your trigger data JSON schema as simple as possible">
+    Although the LLM can fill in the trigger data for the workflow, it's best to
+    keep the trigger data JSON schema as simple as possible to aid with
+    accuracy.
+  </Accordion>
+</AccordionGroup>
+
+## Example prompts for triggering workflows
+
+Here are some example prompts for invoking your workflows as tools in your AI Agent:
+
+- "Trigger the comment-created workflow for the current user."
+- "When the task completes, notify the user using the task-completed workflow."
+- "Send all of the users in the engineering team a welcome message using the welcome-user workflow."
diff --git a/content/developer-tools/agent-toolkit/working-with-environments.mdx b/content/developer-tools/agent-toolkit/working-with-environments.mdx
new file mode 100644
index 000000000..3f368fecc
--- /dev/null
+++ b/content/developer-tools/agent-toolkit/working-with-environments.mdx
@@ -0,0 +1,36 @@
+---
+title: Working with environments in the Knock agent toolkit
+description: Learn how the Knock agent toolkit operates across multiple environments in your Knock account.
+section: Developer tools
+---
+
+The Knock agent toolkit allows you to work across multiple Knock environments.
+
+By default, the toolkit will operate in the `development` environment for all mutation operations. There are times however where you may want your agent to be able to operate across multiple environments, like when the agent has access to creating workflows (which can only be done in the `development` environment), and also executing those workflows in a different environment.
+
+## Setting the environment on initialization
+
+If you want to constrain your agent to operate in a specific Knock environment, you can set the environment on initialization. By default this will be the `development` environment.
+
+```typescript
+const toolkit = await createToolkit({
+  serviceToken: process.env.KNOCK_SERVICE_TOKEN!,
+  environment: "production",
+});
+```
+
+## Setting the environment in a prompt
+
+If you want to allow the Agent to operate across multiple environments, you can also set the environment in a prompt:
+
+```plaintext
+You are operating in the Knock production environment.
+
+Trigger the welcome workflow for the current user.
+```
+
+This will ensure that the `environment` parameter is passed to the trigger workflow tool call, forcing the workflow to be triggered in the `production` environment.
+
+## Workflows-as-tools and environments
+
+If you're using workflows-as-tools, it's recommended that you set the environment on initialization of the toolkit such that the Agent can only find and trigger workflows in a specific environment.
diff --git a/content/developer-tools/building-with-llms.mdx b/content/developer-tools/building-with-llms.mdx
new file mode 100644
index 000000000..736d308e3
--- /dev/null
+++ b/content/developer-tools/building-with-llms.mdx
@@ -0,0 +1,27 @@
+---
+title: Building with LLMs
+description: Use LLMs to assist in integrating Knock into your application.
+section: Developer tools
+---
+
+You can use large language models (LLMs) to assist in integrating Knock into your application. We provide a set of tools to help you if you're using an LLM in your integration, like when using an AI-assisted editor such as Cursor, VS Code with Copilot, or Windsurf.
+
+## Plain text docs
+
+Every page on our docs site is accessible as a plain text file by appending a `.md` extension. For example, this page is accessible as [`building-with-llms.md`](/developer-tools/building-with-llms.md). Our plain text pages are useful to feed to an LLM when building your integration.
+
+We also host an [`/llms.txt`](https://docs.knock.app/llms.txt) and [`/llms-full.txt`](https://docs.knock.app/llms-full.txt) files which instructs AI tools and agents how to retrieve the plain text versions of our pages.
+
+## Knock Model Context Protocol (MCP) Server
+
+We ship an MCP server that exposes the primitives of Knock to LLMs and AI agents via the Model Context Protocol.
+
+You can use the Knock MCP server to aid in building your Knock integration, and to also integrate Knock into any MCP client compatible agent applications.
+
+Learn more in our [MCP Server](/developer-tools/mcp-server) docs.
+
+## Knock agent toolkit SDK
+
+We provide an Agent Toolkit that allows you to integrate Knock via function calling to AI agent workflows. Using the agent toolkit gives your AI agents the ability to send cross-channel messaging to your customers, as well as powering human-in-the-loop interactions.
+
+Learn more in our [Agent Toolkit](/developer-tools/agent-toolkit/overview) docs.
diff --git a/content/developer-tools/mcp-server.mdx b/content/developer-tools/mcp-server.mdx
new file mode 100644
index 000000000..d79359b9f
--- /dev/null
+++ b/content/developer-tools/mcp-server.mdx
@@ -0,0 +1,141 @@
+---
+title: Model Context Protocol (MCP) server
+description: Use the Knock MCP server to make Knock accessible to LLMs and AI agents via tool calling.
+section: Developer tools
+---
+
+<Callout
+  emoji="🚧"
+  text={
+    <>
+      <strong>Note</strong>: the Knock MCP server is currently in beta. Due to
+      the non-deterministic nature of LLMs it's recommended that you test
+      running the MCP against resources in your development environment before
+      running it in production.
+    </>
+  }
+/>
+
+Knock ships an MCP server that exposes the primitives of Knock to LLMs and AI via the <a href="https://modelcontextprotocol.io/" target="_blank">Model Context Protocol (MCP)</a> so that your AI agents can discover and use Knock via tool calling.
+
+Here are some examples of how you can use the MCP server in your workflow:
+
+- **Create workflows using natural language.** "Create a welcome email workflow for my B2B SaaS app."
+- **Trigger a specific workflow to test your integration.** "Trigger the comment-created workflow for Dennis Nedry."
+- **Create a set of test user and tenant data in your account.** "Create a user called Dennis Nedry and a tenant called acme-corp."
+
+## Get started
+
+To get started with the MCP server, you'll need to create a [service token](/developer-tools/service-tokens) to use to authenticate against your Knock account. You can do so under the **Settings** > **Service tokens** page in the Knock dashboard.
+
+Once you have your service, you can then setup the MCP Server in any MCP Client-compatible AI application. We've added the setup instructions below for both Cursor and Claude Desktop, but the same instructions apply to any other MCP Client-compatible application.
+
+**Note**: To run the local MCP server you must have Node 20 or higher installed and accessible globally on your system. You can test this by running `node --version` in your terminal.
+
+### Cursor
+
+1. Go to your Cursor settings and find the "MCP" section
+2. Click "Add new global MCP server"
+3. Inside of your `mcp.json` file under the `mcpServers` key, add the following:
+
+```json
+{
+  "knock": {
+    "command": "npx",
+    "args": [
+      "-y",
+      "@knocklabs/agent-toolkit",
+      "-p",
+      "local-mcp",
+      "--service-token",
+      "YOUR-SERVICE-TOKEN"
+    ],
+    "name": "Knock MCP Server"
+  }
+}
+```
+
+### Claude Desktop
+
+1. Open the Claude Desktop settings and find the "Developer" section
+2. Click to "Edit Config"
+3. Open your `claude_desktop_config.json` file in your preferred text editor
+4. Add the following to the `mcpServers` section (or add the key if it doesn't exist):
+
+```json
+{
+  "knock": {
+    "command": "npx",
+    "args": [
+      "-y",
+      "@knocklabs/agent-toolkit",
+      "-p",
+      "local-mcp",
+      "--service-token",
+      "YOUR-SERVICE-TOKEN"
+    ]
+  }
+}
+```
+
+## Configuring the available tools
+
+It's not recommended to expose all tools that the Knock MCP server has to the LLM. Instead, you should expose only the tools that are required to complete the task at hand. You can configure the available tools by passing in the `--tools` flag when starting the MCP server.
+
+Here are some examples of how you can configure the available tools:
+
+- Expose all tools: `--tools *`
+- Expose all user tools: `--tools users.*`
+- Expose only the `users.create` tool: `--tools users.create`
+
+## Workflows-as-tools
+
+The Knock MCP server also supports exposing your workflows as individual tools. This allows you to provide a specific and precise interface to the LLM for invoking workflow triggers, including describing the data trigger requirements for your workflows.
+
+By default, the MCP server will **not** expose any workflows-as-tools. To opt into this behavior, you can pass in the `--workflows` flag when starting the MCP server.
+
+By default, passing the `--workflows` flag will expose **all** workflows in your Knock account as tools. If you want to control the exact workflows that are exposed as tools, you can pass a list of workflow keys to the `--workflows` flag. For example:
+
+```bash
+--workflows "workflow-key-1,workflow-key-2"
+```
+
+## What tools are available?
+
+The MCP server ships with tools to interact with all Knock resources. You can find the full list of available tools in the [tools reference](/developer-tools/agent-toolkit/tools-reference) of the Knock agent toolkit, which the MCP server is built on top of.
+
+Please note that at this time, the MCP server **does not** ship with any tools to delete resources. This is intentional to prevent the accidental deletion of resources in your Knock account.
+
+### Workflow-specific tools
+
+The Knock MCP server exposes a full suite of tools for creating and managing workflows. Using the MCP server you can:
+
+- Create a workflow with natural language: "create a workflow that sends a welcome email to new users"
+- Create a delay or batch step within your workflow: "delay for 3 days" or "batch for 10 minutes"
+- Create an email step within your workflow: "create a credit card expiring email with a link back to the dashboard"
+- Create an SMS, push, or in-app feed step within your workflow
+
+Using these tools you can create a complex prompt that describes one or more workflows that you'd like to create with natural language.
+
+## Related links
+
+- [Building with LLMs](/developer-tools/building-with-llms)
+- [Knock agent toolkit](/developer-tools/agent-toolkit/overview)
+
+## Frequently asked questions
+
+<AccordionGroup>
+  <Accordion title="Do you support a remote MCP server?">
+    No, currently we support a local MCP server only. We are working
+    on a remote MCP server so that an individual Knock account can be
+    authenticated.
+  </Accordion>
+   <Accordion title="Why do I see a warning about having too many tools?">
+    Some MCP clients will warn you about having more than 50 tools. By default, Knock ships with 30 tools, but when using workflows-as-tools, this number can grow quickly.
+
+    To address this, you should opt into only using the tools you need. For
+    example, if you only use the `users.create` tool, you can expose only that
+    tool by passing in the `--tools` flag.
+
+  </Accordion>
+</AccordionGroup>
diff --git a/data/sidebar.ts b/data/sidebar.ts
index 71b3260fe..99d2a1dca 100644
--- a/data/sidebar.ts
+++ b/data/sidebar.ts
@@ -256,6 +256,44 @@ const sidebarContent: SidebarSection[] = [
         ],
       },
       { slug: "/validating-trigger-data", title: "Validating trigger data" },
+      {
+        slug: "/agent-toolkit",
+        title: "Agent toolkit",
+        isBeta: true,
+        pages: [
+          { slug: "/overview", title: "Overview" },
+          { slug: "/getting-started", title: "Getting started" },
+          {
+            slug: "/workflows-as-tools",
+            title: "Workflows-as-tools",
+          },
+          {
+            slug: "/human-in-the-loop-flows",
+            title: "Human-in-the-loop flows",
+          },
+          {
+            slug: "/providing-context",
+            title: "Providing context",
+          },
+          {
+            slug: "/working-with-environments",
+            title: "Working with environments",
+          },
+          {
+            slug: "/tools-reference",
+            title: "Tools reference",
+          },
+        ],
+      },
+      {
+        slug: "/mcp-server",
+        title: "MCP server",
+        isBeta: true,
+      },
+      {
+        slug: "/building-with-llms",
+        title: "Building with LLMs",
+      },
     ],
   },
 


Reviews:
user: login: rachael-t
body: Some notes from an initial review.

One thought is that in terms of sidebar ordering, I wonder if it would make sense to have "Building with LLMs" first? Since that page seems to provide a more general overview and then points to the MCP and Agent toolkit docs. 
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-04-23T18:20:57Z
user: login: JEverhart383
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-04-24T14:39:19Z
user: login: JEverhart383
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-04-24T14:41:18Z
user: login: JEverhart383
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-04-24T14:44:45Z
user: login: samseely
body: @cjbell  I made some copy edits locally and pushed up. IMO Knock Agent Toolkit should be sentence case so Knock agent toolkit. Also did some rewording etc. 

The larger piece of feedback I have reading through all these is tool visibility. 

A big question I think people will have coming to docs is one we ask in an H2 on the MCP server doc: "What tools are available?"

IMO an important thing is having a quick scannable list of all available tools in our docs. It's basically like the ref that a developer can scan to realize "oh shit this thing does a lot for me"

On the MCP server docs, it tells me to go to agent toolkit docs to see available tools. The agent toolkit docs tell me to go to package docs. The package docs tell me to go to mapi or cli ref, or to look at source code. 

The [source code tools lib](https://github.com/knocklabs/agent-toolkit/tree/main/src/lib/tools) feels like the right place, but it took me too long to get there. Wondering if there's a page we add under agent toolkit called "Tools" or "Tools reference" or something. Basically lists out all tools as well as HITL methods. 
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-04-24T15:26:57Z
user: login: samseely
body: tools ref looks great. left a couple nits but once those in good to go from me
state: APPROVED
author_association: CONTRIBUTOR
submitted_at: 2025-04-25T01:33:13Z

Review comments:
diff_hunk: @@ -0,0 +1,128 @@
+---
+title: Model Context Protocol (MCP) Server
+description: Use the Knock MCP server to supercharge your Knock integration and make Knock accessible to LLMs and AI agents via tool calling.
+section: Developer tools
+---
+
+<Callout
+  emoji="🚧"
+  text={
+    <>
+      <strong>Note</strong>: the MCP server is currently in beta. Due to the
+      non-deterministic nature of LLMs it's recommended that you test running
+      the MCP against resources in your development environment before running
+      it in production.
+    </>
+  }
+/>
+
+Knock ships an MCP server that exposes the primitives of Knock to LLMs and AI via the [Model Context Protocol (MCP)](https://modelcontextprotocol.io/) so that your AI agents can discover and use Knock via tool calling.
path: content/developer-tools/mcp-server.mdx
user: login: rachael-t
body: ```suggestion
Knock ships an MCP server that exposes the primitives of Knock to LLMs and AI via the <a href="https://modelcontextprotocol.io/" target="_blank">Model Context Protocol (MCP)</a> so that your AI agents can discover and use Knock via tool calling.
```
created_at: 2025-04-23T17:42:10Z
author_association: CONTRIBUTOR
diff_hunk: @@ -0,0 +1,128 @@
+---
+title: Model Context Protocol (MCP) Server
+description: Use the Knock MCP server to supercharge your Knock integration and make Knock accessible to LLMs and AI agents via tool calling.
+section: Developer tools
+---
+
+<Callout
+  emoji="🚧"
+  text={
+    <>
+      <strong>Note</strong>: the MCP server is currently in beta. Due to the
+      non-deterministic nature of LLMs it's recommended that you test running
+      the MCP against resources in your development environment before running
+      it in production.
+    </>
+  }
+/>
+
+Knock ships an MCP server that exposes the primitives of Knock to LLMs and AI via the [Model Context Protocol (MCP)](https://modelcontextprotocol.io/) so that your AI agents can discover and use Knock via tool calling.
+
+Here are some examples of how you can use the MCP server in your workflow:
+
+- Create workflows using natural language ("create me a welcome email workflow for my B2B SaaS app")
+- Trigger a specific workflow to test your integration ("trigger the comment-created workflow for dnedry")
+- Create a set of test user and tenant data in your account ("create a user called dnedry and a tenant called acme-corp")
+
+## Get started
+
+To get started with the MCP server, you'll need to create a [service token](/developer-tools/service-tokens) to use to authenticate against your Knock account. You can do so under the "Settings" > "Service tokens" page in the Knock dashboard.
path: content/developer-tools/mcp-server.mdx
user: login: rachael-t
body: ```suggestion
To get started with the MCP server, you'll need to create a [service token](/developer-tools/service-tokens) to use to authenticate against your Knock account. You can do so under the **Settings** > **Service tokens** page in the Knock dashboard.
```
created_at: 2025-04-23T17:43:43Z
author_association: CONTRIBUTOR
diff_hunk: @@ -0,0 +1,128 @@
+---
+title: Model Context Protocol (MCP) Server
+description: Use the Knock MCP server to supercharge your Knock integration and make Knock accessible to LLMs and AI agents via tool calling.
+section: Developer tools
+---
+
+<Callout
+  emoji="🚧"
+  text={
+    <>
+      <strong>Note</strong>: the MCP server is currently in beta. Due to the
+      non-deterministic nature of LLMs it's recommended that you test running
+      the MCP against resources in your development environment before running
+      it in production.
+    </>
+  }
+/>
+
+Knock ships an MCP server that exposes the primitives of Knock to LLMs and AI via the [Model Context Protocol (MCP)](https://modelcontextprotocol.io/) so that your AI agents can discover and use Knock via tool calling.
+
+Here are some examples of how you can use the MCP server in your workflow:
+
+- Create workflows using natural language ("create me a welcome email workflow for my B2B SaaS app")
+- Trigger a specific workflow to test your integration ("trigger the comment-created workflow for dnedry")
+- Create a set of test user and tenant data in your account ("create a user called dnedry and a tenant called acme-corp")
+
+## Get started
+
+To get started with the MCP server, you'll need to create a [service token](/developer-tools/service-tokens) to use to authenticate against your Knock account. You can do so under the "Settings" > "Service tokens" page in the Knock dashboard.
+
+Once you have your service, you can then setup the MCP Server in any MCP Client-compatible AI application. We've added the setup instructions below for both Cursor and Claude Desktop, but the same instructions apply to any other MCP Client-compatible application.
+
+**Note**: To run the local MCP server you must have Node 20 or higher installed and accessible globally on your system. You can test this by running `node --version` in your terminal.
+
+### Cursor
+
+1. Go to your Cursor settings and find the "MCP" section
+2. Click "Add new global MCP server"
+3. Inside of your `mcp.json` file under the `mcpServers` key, add the following:
+
+```json
+{
+  "knock": {
+    "command": "npx",
+    "args": [
+      "-y",
+      "@knocklabs/agent-toolkit",
+      "-p",
+      "local-mcp",
+      "--service-token",
+      "YOUR-SERVICE-TOKEN"
+    ],
+    "name": "Knock MCP Server"
+  }
+}
+```
+
+### Claude Desktop
+
+1. Open the Claude Desktop settings and find the "Developer" section
+2. Click to "Edit Config"
+3. Open your `claude_desktop_config.json` file in your preferred text editor
+4. Add the following to the `mcpServers` section (or add the key if it doesn't exist):
+
+```json
+{
+  "knock": {
+    "command": "npx",
+    "args": [
+      "-y",
+      "@knocklabs/agent-toolkit",
+      "-p",
+      "local-mcp",
+      "--service-token",
+      "YOUR-SERVICE-TOKEN"
+    ]
+  }
+}
+```
+
+## Configuring the available tools
+
+It's not recommended to expose all tools that the Knock MCP server has to the LLM. Instead, you should expose only the tools that are required to complete the task at hand. You can configure the available tools by passing in the `--tools` flag when starting the MCP server.
+
+Here are some examples of how you can configure the available tools:
+
+- Expose all tools: `--tools *`
+- Expose all user tools: `--tools users.*`
+- Expose only the `users.create` tool: `--tools users.create`
+
+## Workflows-as-tools
+
+The Knock MCP server also supports exposing your workflows as individual tools. This allows you to provide a specific and precise interface to the LLM for invoking workflow triggers, including describing the data trigger requirements for your workflows. By default, the MCP server will **not** expose any workflows-as-tools. To opt into this behavior, you can pass in the `--workflows` flag when starting the MCP server.
+
+By default, passing the `--workflows` flag will expose **all** workflows in your Knock account as tools. If you want to control the exact workflows that are exposed as tools, you can pass a list of workflow keys to the `--workflows` flag. For example:
+
+```bash
+--workflows "workflow-key-1,workflow-key-2"
+```
+
+## What tools are available?
+
+The MCP server ships with tools to interact with all Knock resources. You can find the list of available tools in the [Knock Agent Toolkit](/developer-tools/agent-toolkit/overview) documentation.
+
+Please note: at the time of writing, the MCP server **does not** ship with any tools to delete resources. This is intentional to prevent the accidental deletion of resources in your Knock account.
path: content/developer-tools/mcp-server.mdx
user: login: rachael-t
body: ```suggestion
Please note that at this time, the MCP server **does not** ship with any tools to delete resources. This is intentional to prevent the accidental deletion of resources in your Knock account.
```
Open to other suggestions, but this reads a bit weird.

created_at: 2025-04-23T17:47:17Z
author_association: CONTRIBUTOR
diff_hunk: @@ -0,0 +1,74 @@
+---
+title: Workflows-as-tools
+description: Learn how the Agent Toolkit exposes your workflows as tools that your AI Agents can invoke without any integration logic to power cross-channel user messaging.
+section: Developer tools
+---
+
+By default the agent toolkit will expose each of your workflows as a tool that your agents can invoke to power cross-channel messaging. Meaning, if you have a workflow (`comment-created`) within your Knock account, the agent toolkit will expose a `trigger_comment_created_workflow` tool that your agents can invoke to send a notification.
+
+You can think of this as exposing a well-scoped API endpoint that describes exactly how the workflow should be triggered to the LLM/AI Agent. That makes it trivial to build agents that can trigger complex cross-channel messaging flows, with no integration logic.
+
+## Configuring which workflows are exposed as tools
+
+When using the agent toolkit, you can optionally configure exactly which workflows are exposed as tools. To do so, you can set the `permissions.workflows.run` property on the agent toolkit configuration.
+
+In the below example, we're ensuring that **only** the `comment-created`, `task-completed`, and `welcome-user` workflows are exposed as tools to the LLM:
+
+```typescript
+const toolkit = createAgentToolkit({
+  permissions: {
+    workflows: {
+      run: ["comment-created", "task-completed", "welcome-user"],
+    },
+  },
+});
+```
+
+If you wish to omit exposing any workflows as tools, you can set the `permissions.workflows.run` property to an empty array:
+
+```typescript
+const toolkit = createAgentToolkit({
+  permissions: { workflows: { run: [] } },
+});
+```
+
+## Describing the trigger data for each workflow
+
+The trigger data tool created for each workflow exposes the [workflow's trigger data JSON schema](/developer-tools/validating-trigger-data) to the LLM to describe the data payload required to trigger the workflow, and what the shape of that expected data should be.
+
+This allows you to define an explicit contract for your workflow and ensure that the LLM is passing in the correct data when invoking the workflow to send notifications, adding a safe guard so that workflows cannot be triggered with incorrect data supplied.
+
+## Tips for exposing workflows to LLMs
+
+<AccordionGroup>
+  <Accordion title="Use the workflow description to add additional calling context for the LLM">
+    The workflow description is a great place to add additional calling context
+    for the LLM as it is injected into the prompt that exposes the tool. That
+    means you can use the description to add additional calling context, like
+    when the workflow should be used, or what the context of the workflow is.
+  </Accordion>
+  <Accordion title="Limit the workflows that are exposed to the LLM">
+    It's best if you limit the workflows exposed to the LLM as tools to only
+    those that you absolutely know that the LLM can trigger. This helps keep the
+    LLM "focussed" on the task, and sticks to best practice about the total
path: content/developer-tools/agent-toolkit/workflows-as-tools.mdx
user: login: rachael-t
body: ```suggestion
    LLM "focused" on the task, and sticks to best practice about the total
```
created_at: 2025-04-23T17:59:47Z
author_association: CONTRIBUTOR
diff_hunk: @@ -0,0 +1,208 @@
+---
+title: Powering human-in-the-loop flows with the Knock Agent Toolkit
+description: Learn how to use the Knock Agent Toolkit within your AI agent workflows to power rich human-in-the-loop interactions.
+section: Developer tools
+---
+
+The Knock Agent Toolkit allows you to power rich human-in-the-loop interactions. For example, you can use the agent toolkit to create a workflow that lets a person to approve or reject work that the agent has done, powered by Knock's cross-channel messaging workflows.
+
+The Agent Toolkit exposes a set of helper methods that make it trivial for you to wrap your tool calls in requiring human input to proceed, and leveraging Knock's webhook mechanism to handle the asynchronous nature of a human-in-the-loop interaction. Knock takes care of all of the heavy lifting for you, making it easy to build rich human-in-the-loop flows with little effort.
path: content/developer-tools/agent-toolkit/human-in-the-loop-flows.mdx
user: login: rachael-t
body: ```suggestion
The Agent Toolkit exposes a set of helper methods that make it trivial for you to wrap your tool calls in a way that requires human input to proceed, while also leveraging Knock's webhook mechanism to handle the asynchronous nature of a human-in-the-loop interaction. Knock takes care of all the heavy lifting for you, making it easy to build rich human-in-the-loop flows with minimal effort.
```

This first sentence was slightly confusing upon initial reading. This is just a suggestion, but I'm open to others as well. 
created_at: 2025-04-23T18:06:31Z
author_association: CONTRIBUTOR
diff_hunk: @@ -0,0 +1,208 @@
+---
+title: Powering human-in-the-loop flows with the Knock Agent Toolkit
+description: Learn how to use the Knock Agent Toolkit within your AI agent workflows to power rich human-in-the-loop interactions.
+section: Developer tools
+---
+
+The Knock Agent Toolkit allows you to power rich human-in-the-loop interactions. For example, you can use the agent toolkit to create a workflow that lets a person to approve or reject work that the agent has done, powered by Knock's cross-channel messaging workflows.
+
+The Agent Toolkit exposes a set of helper methods that make it trivial for you to wrap your tool calls in requiring human input to proceed, and leveraging Knock's webhook mechanism to handle the asynchronous nature of a human-in-the-loop interaction. Knock takes care of all of the heavy lifting for you, making it easy to build rich human-in-the-loop flows with little effort.
+
+Using Knock it's possible to power human-in-the-loop interactions that:
path: content/developer-tools/agent-toolkit/human-in-the-loop-flows.mdx
user: login: rachael-t
body: ```suggestion
Using Knock, it's possible to power human-in-the-loop interactions that:
```
created_at: 2025-04-23T18:09:26Z
author_association: CONTRIBUTOR
diff_hunk: @@ -0,0 +1,208 @@
+---
+title: Powering human-in-the-loop flows with the Knock Agent Toolkit
+description: Learn how to use the Knock Agent Toolkit within your AI agent workflows to power rich human-in-the-loop interactions.
+section: Developer tools
+---
+
+The Knock Agent Toolkit allows you to power rich human-in-the-loop interactions. For example, you can use the agent toolkit to create a workflow that lets a person to approve or reject work that the agent has done, powered by Knock's cross-channel messaging workflows.
+
+The Agent Toolkit exposes a set of helper methods that make it trivial for you to wrap your tool calls in requiring human input to proceed, and leveraging Knock's webhook mechanism to handle the asynchronous nature of a human-in-the-loop interaction. Knock takes care of all of the heavy lifting for you, making it easy to build rich human-in-the-loop flows with little effort.
+
+Using Knock it's possible to power human-in-the-loop interactions that:
+
+- Send cross-channel notifications to email, SMS, in-app feeds, and workplace chat applications like Slack and MS Teams.
+- Power advanced cross-channel escalation flows to bubble up messages between channels or across team members.
+- Solicit structured input such as approve/reject buttons, or unstructured feedback in the form of text or prompt modifications.
+- Handle long-running async interactions that "interrupt" and "resume" your agent workflows.
+- Give full visibility into the messages sent from your AI agent workflows and track engagement of those messages across channels.
+
+## How Knock powers human-in-the-loop flows
+
+Knock uses [workflows](/concepts/workflows) to power human in the loop messaging across channels. Here's a high-level overview of how this works:
path: content/developer-tools/agent-toolkit/human-in-the-loop-flows.mdx
user: login: rachael-t
body: ```suggestion
Knock uses [workflows](/concepts/workflows) to power human-in-the-loop messaging across channels. Here's a high-level overview of how this works:
```
created_at: 2025-04-23T18:10:06Z
author_association: CONTRIBUTOR
diff_hunk: @@ -0,0 +1,208 @@
+---
+title: Powering human-in-the-loop flows with the Knock Agent Toolkit
+description: Learn how to use the Knock Agent Toolkit within your AI agent workflows to power rich human-in-the-loop interactions.
+section: Developer tools
+---
+
+The Knock Agent Toolkit allows you to power rich human-in-the-loop interactions. For example, you can use the agent toolkit to create a workflow that lets a person to approve or reject work that the agent has done, powered by Knock's cross-channel messaging workflows.
+
+The Agent Toolkit exposes a set of helper methods that make it trivial for you to wrap your tool calls in requiring human input to proceed, and leveraging Knock's webhook mechanism to handle the asynchronous nature of a human-in-the-loop interaction. Knock takes care of all of the heavy lifting for you, making it easy to build rich human-in-the-loop flows with little effort.
+
+Using Knock it's possible to power human-in-the-loop interactions that:
+
+- Send cross-channel notifications to email, SMS, in-app feeds, and workplace chat applications like Slack and MS Teams.
+- Power advanced cross-channel escalation flows to bubble up messages between channels or across team members.
+- Solicit structured input such as approve/reject buttons, or unstructured feedback in the form of text or prompt modifications.
+- Handle long-running async interactions that "interrupt" and "resume" your agent workflows.
+- Give full visibility into the messages sent from your AI agent workflows and track engagement of those messages across channels.
+
+## How Knock powers human-in-the-loop flows
+
+Knock uses [workflows](/concepts/workflows) to power human in the loop messaging across channels. Here's a high-level overview of how this works:
+
+1. You setup a workflow in the Knock dashboard that describes the message to send and the channels to send it to.
+2. Your agent calls to Knock to [trigger the workflow](/send-notifications/trigger-workflows/overview) with a set of recipients and any additional context for the request.
path: content/developer-tools/agent-toolkit/human-in-the-loop-flows.mdx
user: login: rachael-t
body: ```suggestion
2. Your agent calls to Knock to [trigger the workflow](/send-notifications/triggering-workflows/overview) with a set of recipients and any additional context for the request.
```
created_at: 2025-04-23T18:11:18Z
author_association: CONTRIBUTOR
diff_hunk: @@ -0,0 +1,208 @@
+---
+title: Powering human-in-the-loop flows with the Knock Agent Toolkit
+description: Learn how to use the Knock Agent Toolkit within your AI agent workflows to power rich human-in-the-loop interactions.
+section: Developer tools
+---
+
+The Knock Agent Toolkit allows you to power rich human-in-the-loop interactions. For example, you can use the agent toolkit to create a workflow that lets a person to approve or reject work that the agent has done, powered by Knock's cross-channel messaging workflows.
+
+The Agent Toolkit exposes a set of helper methods that make it trivial for you to wrap your tool calls in requiring human input to proceed, and leveraging Knock's webhook mechanism to handle the asynchronous nature of a human-in-the-loop interaction. Knock takes care of all of the heavy lifting for you, making it easy to build rich human-in-the-loop flows with little effort.
+
+Using Knock it's possible to power human-in-the-loop interactions that:
+
+- Send cross-channel notifications to email, SMS, in-app feeds, and workplace chat applications like Slack and MS Teams.
+- Power advanced cross-channel escalation flows to bubble up messages between channels or across team members.
+- Solicit structured input such as approve/reject buttons, or unstructured feedback in the form of text or prompt modifications.
+- Handle long-running async interactions that "interrupt" and "resume" your agent workflows.
+- Give full visibility into the messages sent from your AI agent workflows and track engagement of those messages across channels.
+
+## How Knock powers human-in-the-loop flows
+
+Knock uses [workflows](/concepts/workflows) to power human in the loop messaging across channels. Here's a high-level overview of how this works:
+
+1. You setup a workflow in the Knock dashboard that describes the message to send and the channels to send it to.
+2. Your agent calls to Knock to [trigger the workflow](/send-notifications/trigger-workflows/overview) with a set of recipients and any additional context for the request.
+3. Your user receives the message on the channel, which includes a the context for the request and a set of actions to take.
path: content/developer-tools/agent-toolkit/human-in-the-loop-flows.mdx
user: login: rachael-t
body: ```suggestion
3. Your user receives the message on the channel, which includes the context for the request and a set of actions to take.
```
created_at: 2025-04-23T18:12:03Z
author_association: CONTRIBUTOR
diff_hunk: @@ -0,0 +1,208 @@
+---
+title: Powering human-in-the-loop flows with the Knock Agent Toolkit
+description: Learn how to use the Knock Agent Toolkit within your AI agent workflows to power rich human-in-the-loop interactions.
+section: Developer tools
+---
+
+The Knock Agent Toolkit allows you to power rich human-in-the-loop interactions. For example, you can use the agent toolkit to create a workflow that lets a person to approve or reject work that the agent has done, powered by Knock's cross-channel messaging workflows.
+
+The Agent Toolkit exposes a set of helper methods that make it trivial for you to wrap your tool calls in requiring human input to proceed, and leveraging Knock's webhook mechanism to handle the asynchronous nature of a human-in-the-loop interaction. Knock takes care of all of the heavy lifting for you, making it easy to build rich human-in-the-loop flows with little effort.
+
+Using Knock it's possible to power human-in-the-loop interactions that:
+
+- Send cross-channel notifications to email, SMS, in-app feeds, and workplace chat applications like Slack and MS Teams.
+- Power advanced cross-channel escalation flows to bubble up messages between channels or across team members.
+- Solicit structured input such as approve/reject buttons, or unstructured feedback in the form of text or prompt modifications.
+- Handle long-running async interactions that "interrupt" and "resume" your agent workflows.
+- Give full visibility into the messages sent from your AI agent workflows and track engagement of those messages across channels.
+
+## How Knock powers human-in-the-loop flows
+
+Knock uses [workflows](/concepts/workflows) to power human in the loop messaging across channels. Here's a high-level overview of how this works:
+
+1. You setup a workflow in the Knock dashboard that describes the message to send and the channels to send it to.
+2. Your agent calls to Knock to [trigger the workflow](/send-notifications/trigger-workflows/overview) with a set of recipients and any additional context for the request.
+3. Your user receives the message on the channel, which includes a the context for the request and a set of actions to take.
+4. The user then interacts with the message and the result is recorded back to Knock.
+5. Knock then triggers an [outbound webhook](/developer-tools/outbound-webhooks/overview) back to your agent application with the result of the interaction.
+6. Your agent application can then use the incoming interaction event from Knock to resume execution, or respond to the interaction.
+
+## Helper methods
+
+<Callout
+  emoji="💡"
+  text={
+    <>
+      <strong>Note</strong>: The following helper methods are only exposed for
+      the AI SDK. If you're using the Knock Agent toolkit with another Agent
+      framework and need to implement a custom flow, please reach out to us at{" "}
+      <a href="mailto:support@knock.app">support@knock.app</a>.
+    </>
+  }
+/>
+
+The Knock Agent Toolkit exposes a set of helper methods that you can use to power human-in-the-loop flows for common cases, and low-level primitives should you need to implement a custom flow.
+
+### `toolkit.requiresHumanInput`
+
+The `requiresHumanInput` helper method allows you to wrap a tool in requiring human input to proceed. When a tool is wrapped with this method, when the LLM tries to invoke the call it will instead delegate the tool call to Knock, passing the tool execution context to the Knock workflow.
+
+```typescript title="Wrap tool in requiring input"
+import { createToolkit } from "@knocklabs/agent-toolkit/ai-sdk";
+
+const toolkit = await createToolkit({
+  serviceToken: process.env.KNOCK_SERVICE_TOKEN,
+});
+
+const { classifyWork: classifyToolRequiringInput } = toolkit.requireHumanInput(
+  { classifyWork },
+  {
+    // (required) The key of the workflow to trigger
+    workflow: "approve-classification",
+    // (required) The list of recipients to trigger the workflow for
+    recipients: ["user_123"],
+    // (optional) Any additional data to pass along with the request
+    data: {},
+  },
+);
+```
+
+Calling `requireHumanInput` will return a new tool that you pass in place of the original tool in your model. When the LLM invokes the new tool, it will instead delegate the tool call to Knock, passing the tool execution context to the Knock workflow.
+
+Note: when the LLM invokes the new tool, it will appear as if the tool-call completed, albeit with a result that indicates that the tool is still waiting for human input. This is expected behavior.
path: content/developer-tools/agent-toolkit/human-in-the-loop-flows.mdx
user: login: rachael-t
body: Unsure if we want to make this a `<Callout>`?
created_at: 2025-04-23T18:13:41Z
author_association: CONTRIBUTOR
diff_hunk: @@ -0,0 +1,208 @@
+---
+title: Powering human-in-the-loop flows with the Knock Agent Toolkit
+description: Learn how to use the Knock Agent Toolkit within your AI agent workflows to power rich human-in-the-loop interactions.
+section: Developer tools
+---
+
+The Knock Agent Toolkit allows you to power rich human-in-the-loop interactions. For example, you can use the agent toolkit to create a workflow that lets a person to approve or reject work that the agent has done, powered by Knock's cross-channel messaging workflows.
+
+The Agent Toolkit exposes a set of helper methods that make it trivial for you to wrap your tool calls in requiring human input to proceed, and leveraging Knock's webhook mechanism to handle the asynchronous nature of a human-in-the-loop interaction. Knock takes care of all of the heavy lifting for you, making it easy to build rich human-in-the-loop flows with little effort.
+
+Using Knock it's possible to power human-in-the-loop interactions that:
+
+- Send cross-channel notifications to email, SMS, in-app feeds, and workplace chat applications like Slack and MS Teams.
+- Power advanced cross-channel escalation flows to bubble up messages between channels or across team members.
+- Solicit structured input such as approve/reject buttons, or unstructured feedback in the form of text or prompt modifications.
+- Handle long-running async interactions that "interrupt" and "resume" your agent workflows.
+- Give full visibility into the messages sent from your AI agent workflows and track engagement of those messages across channels.
+
+## How Knock powers human-in-the-loop flows
+
+Knock uses [workflows](/concepts/workflows) to power human in the loop messaging across channels. Here's a high-level overview of how this works:
+
+1. You setup a workflow in the Knock dashboard that describes the message to send and the channels to send it to.
+2. Your agent calls to Knock to [trigger the workflow](/send-notifications/trigger-workflows/overview) with a set of recipients and any additional context for the request.
+3. Your user receives the message on the channel, which includes a the context for the request and a set of actions to take.
+4. The user then interacts with the message and the result is recorded back to Knock.
+5. Knock then triggers an [outbound webhook](/developer-tools/outbound-webhooks/overview) back to your agent application with the result of the interaction.
+6. Your agent application can then use the incoming interaction event from Knock to resume execution, or respond to the interaction.
+
+## Helper methods
+
+<Callout
+  emoji="💡"
+  text={
+    <>
+      <strong>Note</strong>: The following helper methods are only exposed for
+      the AI SDK. If you're using the Knock Agent toolkit with another Agent
+      framework and need to implement a custom flow, please reach out to us at{" "}
+      <a href="mailto:support@knock.app">support@knock.app</a>.
+    </>
+  }
+/>
+
+The Knock Agent Toolkit exposes a set of helper methods that you can use to power human-in-the-loop flows for common cases, and low-level primitives should you need to implement a custom flow.
+
+### `toolkit.requiresHumanInput`
+
+The `requiresHumanInput` helper method allows you to wrap a tool in requiring human input to proceed. When a tool is wrapped with this method, when the LLM tries to invoke the call it will instead delegate the tool call to Knock, passing the tool execution context to the Knock workflow.
+
+```typescript title="Wrap tool in requiring input"
+import { createToolkit } from "@knocklabs/agent-toolkit/ai-sdk";
+
+const toolkit = await createToolkit({
+  serviceToken: process.env.KNOCK_SERVICE_TOKEN,
+});
+
+const { classifyWork: classifyToolRequiringInput } = toolkit.requireHumanInput(
+  { classifyWork },
+  {
+    // (required) The key of the workflow to trigger
+    workflow: "approve-classification",
+    // (required) The list of recipients to trigger the workflow for
+    recipients: ["user_123"],
+    // (optional) Any additional data to pass along with the request
+    data: {},
+  },
+);
+```
+
+Calling `requireHumanInput` will return a new tool that you pass in place of the original tool in your model. When the LLM invokes the new tool, it will instead delegate the tool call to Knock, passing the tool execution context to the Knock workflow.
+
+Note: when the LLM invokes the new tool, it will appear as if the tool-call completed, albeit with a result that indicates that the tool is still waiting for human input. This is expected behavior.
+
+### `toolkit.handleMessageInteracted`
+
+The `handleMessageInteracted` helper method allows you to handle an incoming `message.interacted` event from Knock and determine if there's an interaction with the message that should be handled by your agent workflow.
+
+```typescript title="Handling an incoming interaction"
+import { createToolkit } from "@knocklabs/agent-toolkit/ai-sdk";
+
+const toolkit = await createToolkit({
+  serviceToken: process.env.KNOCK_SERVICE_TOKEN,
+});
+
+function handleIncomingInteraction(event) {
+  const interactionEvent = toolkit.handleMessageInteracted(event);
+
+  if (
+    interactionEvent &&
+    interactionEvent.workflow === "my-approval-workflow" &&
+    interactionEvent.interaction.action === "approved"
+  ) {
+    // Do something as a result of the approval
+  }
+}
+```
+
+### `toolkit.resumeToolExecution`
+
+The `resumeToolExecution` helper method allows you to resume tool execution after a human has interacted with the message and you have received an affirmative response to proceed.
+
+You pass the `resumeToolExecution` method the `DeferredToolCallInteractionResult` that you've received from Knock via the `handleMessageInteracted` method. Here's an example of how you might use this method:
+
+```typescript title="Resuming tool execution"
+import { createToolkit } from "@knocklabs/agent-toolkit/ai-sdk";
+
+const toolkit = await createToolkit({
+  serviceToken: process.env.KNOCK_SERVICE_TOKEN,
+});
+
+function handleIncomingInteraction(event) {
+  const interactionEvent = toolkit.handleMessageInteracted(event);
+
+  if (interactionEvent && interactionEvent.hasToolCall) {
+    const toolResult = await toolkit.resumeToolExecution(interactionEvent);
+    // Do something with the tool result
+  }
+}
+```
+
+When using the `resumeToolExecution` method, you must have first registered any tools that require human input using the `requiresHumanInput` method. This ensures that the toolkit has access to the necessary information to resume the tool execution.
+
+In the AI SDK, the `resumeToolExecution` method will return a tool status object where you can access the result under the `result` property. The original `toolCallId` is also included.
+
+## Example: In-app approval flow
+
+In this guide we show you how to setup an approval flow that sends an in-app notification to a notification feed requesting approval when the agent wishes to invoke a particular tool.
+
+<Steps>
+  <Step title="Setting up a workflow to power approvals">
+    To start, you'll want to setup a Knock workflow with a single, in-app feed channel step that sends an approval message to an in-app feed. You can find a workflow template for this in the [workflow templates repository](https://github.com/knocklabs/workflow-templates/blob/main/workflows/approval-workflow.json).
path: content/developer-tools/agent-toolkit/human-in-the-loop-flows.mdx
user: login: rachael-t
body: This GitHub repo returns a 404?
created_at: 2025-04-23T18:15:20Z
author_association: CONTRIBUTOR
diff_hunk: @@ -0,0 +1,208 @@
+---
+title: Powering human-in-the-loop flows with the Knock Agent Toolkit
+description: Learn how to use the Knock Agent Toolkit within your AI agent workflows to power rich human-in-the-loop interactions.
+section: Developer tools
+---
+
+The Knock Agent Toolkit allows you to power rich human-in-the-loop interactions. For example, you can use the agent toolkit to create a workflow that lets a person to approve or reject work that the agent has done, powered by Knock's cross-channel messaging workflows.
+
+The Agent Toolkit exposes a set of helper methods that make it trivial for you to wrap your tool calls in requiring human input to proceed, and leveraging Knock's webhook mechanism to handle the asynchronous nature of a human-in-the-loop interaction. Knock takes care of all of the heavy lifting for you, making it easy to build rich human-in-the-loop flows with little effort.
+
+Using Knock it's possible to power human-in-the-loop interactions that:
+
+- Send cross-channel notifications to email, SMS, in-app feeds, and workplace chat applications like Slack and MS Teams.
+- Power advanced cross-channel escalation flows to bubble up messages between channels or across team members.
+- Solicit structured input such as approve/reject buttons, or unstructured feedback in the form of text or prompt modifications.
+- Handle long-running async interactions that "interrupt" and "resume" your agent workflows.
+- Give full visibility into the messages sent from your AI agent workflows and track engagement of those messages across channels.
+
+## How Knock powers human-in-the-loop flows
+
+Knock uses [workflows](/concepts/workflows) to power human in the loop messaging across channels. Here's a high-level overview of how this works:
+
+1. You setup a workflow in the Knock dashboard that describes the message to send and the channels to send it to.
+2. Your agent calls to Knock to [trigger the workflow](/send-notifications/trigger-workflows/overview) with a set of recipients and any additional context for the request.
+3. Your user receives the message on the channel, which includes a the context for the request and a set of actions to take.
+4. The user then interacts with the message and the result is recorded back to Knock.
+5. Knock then triggers an [outbound webhook](/developer-tools/outbound-webhooks/overview) back to your agent application with the result of the interaction.
+6. Your agent application can then use the incoming interaction event from Knock to resume execution, or respond to the interaction.
+
+## Helper methods
+
+<Callout
+  emoji="💡"
+  text={
+    <>
+      <strong>Note</strong>: The following helper methods are only exposed for
+      the AI SDK. If you're using the Knock Agent toolkit with another Agent
+      framework and need to implement a custom flow, please reach out to us at{" "}
+      <a href="mailto:support@knock.app">support@knock.app</a>.
+    </>
+  }
+/>
+
+The Knock Agent Toolkit exposes a set of helper methods that you can use to power human-in-the-loop flows for common cases, and low-level primitives should you need to implement a custom flow.
+
+### `toolkit.requiresHumanInput`
+
+The `requiresHumanInput` helper method allows you to wrap a tool in requiring human input to proceed. When a tool is wrapped with this method, when the LLM tries to invoke the call it will instead delegate the tool call to Knock, passing the tool execution context to the Knock workflow.
+
+```typescript title="Wrap tool in requiring input"
+import { createToolkit } from "@knocklabs/agent-toolkit/ai-sdk";
+
+const toolkit = await createToolkit({
+  serviceToken: process.env.KNOCK_SERVICE_TOKEN,
+});
+
+const { classifyWork: classifyToolRequiringInput } = toolkit.requireHumanInput(
+  { classifyWork },
+  {
+    // (required) The key of the workflow to trigger
+    workflow: "approve-classification",
+    // (required) The list of recipients to trigger the workflow for
+    recipients: ["user_123"],
+    // (optional) Any additional data to pass along with the request
+    data: {},
+  },
+);
+```
+
+Calling `requireHumanInput` will return a new tool that you pass in place of the original tool in your model. When the LLM invokes the new tool, it will instead delegate the tool call to Knock, passing the tool execution context to the Knock workflow.
+
+Note: when the LLM invokes the new tool, it will appear as if the tool-call completed, albeit with a result that indicates that the tool is still waiting for human input. This is expected behavior.
+
+### `toolkit.handleMessageInteracted`
+
+The `handleMessageInteracted` helper method allows you to handle an incoming `message.interacted` event from Knock and determine if there's an interaction with the message that should be handled by your agent workflow.
+
+```typescript title="Handling an incoming interaction"
+import { createToolkit } from "@knocklabs/agent-toolkit/ai-sdk";
+
+const toolkit = await createToolkit({
+  serviceToken: process.env.KNOCK_SERVICE_TOKEN,
+});
+
+function handleIncomingInteraction(event) {
+  const interactionEvent = toolkit.handleMessageInteracted(event);
+
+  if (
+    interactionEvent &&
+    interactionEvent.workflow === "my-approval-workflow" &&
+    interactionEvent.interaction.action === "approved"
+  ) {
+    // Do something as a result of the approval
+  }
+}
+```
+
+### `toolkit.resumeToolExecution`
+
+The `resumeToolExecution` helper method allows you to resume tool execution after a human has interacted with the message and you have received an affirmative response to proceed.
+
+You pass the `resumeToolExecution` method the `DeferredToolCallInteractionResult` that you've received from Knock via the `handleMessageInteracted` method. Here's an example of how you might use this method:
+
+```typescript title="Resuming tool execution"
+import { createToolkit } from "@knocklabs/agent-toolkit/ai-sdk";
+
+const toolkit = await createToolkit({
+  serviceToken: process.env.KNOCK_SERVICE_TOKEN,
+});
+
+function handleIncomingInteraction(event) {
+  const interactionEvent = toolkit.handleMessageInteracted(event);
+
+  if (interactionEvent && interactionEvent.hasToolCall) {
+    const toolResult = await toolkit.resumeToolExecution(interactionEvent);
+    // Do something with the tool result
+  }
+}
+```
+
+When using the `resumeToolExecution` method, you must have first registered any tools that require human input using the `requiresHumanInput` method. This ensures that the toolkit has access to the necessary information to resume the tool execution.
+
+In the AI SDK, the `resumeToolExecution` method will return a tool status object where you can access the result under the `result` property. The original `toolCallId` is also included.
+
+## Example: In-app approval flow
+
+In this guide we show you how to setup an approval flow that sends an in-app notification to a notification feed requesting approval when the agent wishes to invoke a particular tool.
+
+<Steps>
+  <Step title="Setting up a workflow to power approvals">
+    To start, you'll want to setup a Knock workflow with a single, in-app feed channel step that sends an approval message to an in-app feed. You can find a workflow template for this in the [workflow templates repository](https://github.com/knocklabs/workflow-templates/blob/main/workflows/approval-workflow.json).
+  </Step>
+  <Step title="Handling the feed interaction">
+    Next, you'll need to add an interaction handler such that when a user taps on the approve/reject buttons in the notification feed that 
path: content/developer-tools/agent-toolkit/human-in-the-loop-flows.mdx
user: login: rachael-t
body: Seems like this step wasn't completed
created_at: 2025-04-23T18:15:55Z
author_association: CONTRIBUTOR
diff_hunk: @@ -0,0 +1,208 @@
+---
+title: Powering human-in-the-loop flows with the Knock Agent Toolkit
+description: Learn how to use the Knock Agent Toolkit within your AI agent workflows to power rich human-in-the-loop interactions.
+section: Developer tools
+---
+
+The Knock Agent Toolkit allows you to power rich human-in-the-loop interactions. For example, you can use the agent toolkit to create a workflow that lets a person to approve or reject work that the agent has done, powered by Knock's cross-channel messaging workflows.
+
+The Agent Toolkit exposes a set of helper methods that make it trivial for you to wrap your tool calls in requiring human input to proceed, and leveraging Knock's webhook mechanism to handle the asynchronous nature of a human-in-the-loop interaction. Knock takes care of all of the heavy lifting for you, making it easy to build rich human-in-the-loop flows with little effort.
+
+Using Knock it's possible to power human-in-the-loop interactions that:
+
+- Send cross-channel notifications to email, SMS, in-app feeds, and workplace chat applications like Slack and MS Teams.
+- Power advanced cross-channel escalation flows to bubble up messages between channels or across team members.
+- Solicit structured input such as approve/reject buttons, or unstructured feedback in the form of text or prompt modifications.
+- Handle long-running async interactions that "interrupt" and "resume" your agent workflows.
+- Give full visibility into the messages sent from your AI agent workflows and track engagement of those messages across channels.
+
+## How Knock powers human-in-the-loop flows
+
+Knock uses [workflows](/concepts/workflows) to power human in the loop messaging across channels. Here's a high-level overview of how this works:
+
+1. You setup a workflow in the Knock dashboard that describes the message to send and the channels to send it to.
+2. Your agent calls to Knock to [trigger the workflow](/send-notifications/trigger-workflows/overview) with a set of recipients and any additional context for the request.
+3. Your user receives the message on the channel, which includes a the context for the request and a set of actions to take.
+4. The user then interacts with the message and the result is recorded back to Knock.
+5. Knock then triggers an [outbound webhook](/developer-tools/outbound-webhooks/overview) back to your agent application with the result of the interaction.
+6. Your agent application can then use the incoming interaction event from Knock to resume execution, or respond to the interaction.
+
+## Helper methods
+
+<Callout
+  emoji="💡"
+  text={
+    <>
+      <strong>Note</strong>: The following helper methods are only exposed for
+      the AI SDK. If you're using the Knock Agent toolkit with another Agent
+      framework and need to implement a custom flow, please reach out to us at{" "}
+      <a href="mailto:support@knock.app">support@knock.app</a>.
+    </>
+  }
+/>
+
+The Knock Agent Toolkit exposes a set of helper methods that you can use to power human-in-the-loop flows for common cases, and low-level primitives should you need to implement a custom flow.
+
+### `toolkit.requiresHumanInput`
+
+The `requiresHumanInput` helper method allows you to wrap a tool in requiring human input to proceed. When a tool is wrapped with this method, when the LLM tries to invoke the call it will instead delegate the tool call to Knock, passing the tool execution context to the Knock workflow.
+
+```typescript title="Wrap tool in requiring input"
+import { createToolkit } from "@knocklabs/agent-toolkit/ai-sdk";
+
+const toolkit = await createToolkit({
+  serviceToken: process.env.KNOCK_SERVICE_TOKEN,
+});
+
+const { classifyWork: classifyToolRequiringInput } = toolkit.requireHumanInput(
+  { classifyWork },
+  {
+    // (required) The key of the workflow to trigger
+    workflow: "approve-classification",
+    // (required) The list of recipients to trigger the workflow for
+    recipients: ["user_123"],
+    // (optional) Any additional data to pass along with the request
+    data: {},
+  },
+);
+```
+
+Calling `requireHumanInput` will return a new tool that you pass in place of the original tool in your model. When the LLM invokes the new tool, it will instead delegate the tool call to Knock, passing the tool execution context to the Knock workflow.
+
+Note: when the LLM invokes the new tool, it will appear as if the tool-call completed, albeit with a result that indicates that the tool is still waiting for human input. This is expected behavior.
+
+### `toolkit.handleMessageInteracted`
+
+The `handleMessageInteracted` helper method allows you to handle an incoming `message.interacted` event from Knock and determine if there's an interaction with the message that should be handled by your agent workflow.
+
+```typescript title="Handling an incoming interaction"
+import { createToolkit } from "@knocklabs/agent-toolkit/ai-sdk";
+
+const toolkit = await createToolkit({
+  serviceToken: process.env.KNOCK_SERVICE_TOKEN,
+});
+
+function handleIncomingInteraction(event) {
+  const interactionEvent = toolkit.handleMessageInteracted(event);
+
+  if (
+    interactionEvent &&
+    interactionEvent.workflow === "my-approval-workflow" &&
+    interactionEvent.interaction.action === "approved"
+  ) {
+    // Do something as a result of the approval
+  }
+}
+```
+
+### `toolkit.resumeToolExecution`
+
+The `resumeToolExecution` helper method allows you to resume tool execution after a human has interacted with the message and you have received an affirmative response to proceed.
+
+You pass the `resumeToolExecution` method the `DeferredToolCallInteractionResult` that you've received from Knock via the `handleMessageInteracted` method. Here's an example of how you might use this method:
+
+```typescript title="Resuming tool execution"
+import { createToolkit } from "@knocklabs/agent-toolkit/ai-sdk";
+
+const toolkit = await createToolkit({
+  serviceToken: process.env.KNOCK_SERVICE_TOKEN,
+});
+
+function handleIncomingInteraction(event) {
+  const interactionEvent = toolkit.handleMessageInteracted(event);
+
+  if (interactionEvent && interactionEvent.hasToolCall) {
+    const toolResult = await toolkit.resumeToolExecution(interactionEvent);
+    // Do something with the tool result
+  }
+}
+```
+
+When using the `resumeToolExecution` method, you must have first registered any tools that require human input using the `requiresHumanInput` method. This ensures that the toolkit has access to the necessary information to resume the tool execution.
+
+In the AI SDK, the `resumeToolExecution` method will return a tool status object where you can access the result under the `result` property. The original `toolCallId` is also included.
+
+## Example: In-app approval flow
+
+In this guide we show you how to setup an approval flow that sends an in-app notification to a notification feed requesting approval when the agent wishes to invoke a particular tool.
+
+<Steps>
+  <Step title="Setting up a workflow to power approvals">
+    To start, you'll want to setup a Knock workflow with a single, in-app feed channel step that sends an approval message to an in-app feed. You can find a workflow template for this in the [workflow templates repository](https://github.com/knocklabs/workflow-templates/blob/main/workflows/approval-workflow.json).
+  </Step>
+  <Step title="Handling the feed interaction">
+    Next, you'll need to add an interaction handler such that when a user taps on the approve/reject buttons in the notification feed that 
+  </Step>
+  <Step title="Setting up an outbound webhook in Knock">
+    A human in the loop interaction is inherently an asynchronous action, and so requires that we might need to handle the approval at some later point. Knock uses [outbound webhooks](/developer-tools/outbound-webhooks/overview) to forward your events to your application, helping to implement this asynchronous behavior.
path: content/developer-tools/agent-toolkit/human-in-the-loop-flows.mdx
user: login: rachael-t
body: ```suggestion
    A human-in-the-loop interaction is inherently an asynchronous action, and therefore requires that we might need to handle the approval at some later point. Knock uses [outbound webhooks](/developer-tools/outbound-webhooks/overview) to forward your events to your application, helping to implement this asynchronous behavior.
```
created_at: 2025-04-23T18:16:36Z
author_association: CONTRIBUTOR
diff_hunk: @@ -0,0 +1,208 @@
+---
+title: Powering human-in-the-loop flows with the Knock Agent Toolkit
+description: Learn how to use the Knock Agent Toolkit within your AI agent workflows to power rich human-in-the-loop interactions.
+section: Developer tools
+---
+
+The Knock Agent Toolkit allows you to power rich human-in-the-loop interactions. For example, you can use the agent toolkit to create a workflow that lets a person to approve or reject work that the agent has done, powered by Knock's cross-channel messaging workflows.
+
+The Agent Toolkit exposes a set of helper methods that make it trivial for you to wrap your tool calls in requiring human input to proceed, and leveraging Knock's webhook mechanism to handle the asynchronous nature of a human-in-the-loop interaction. Knock takes care of all of the heavy lifting for you, making it easy to build rich human-in-the-loop flows with little effort.
+
+Using Knock it's possible to power human-in-the-loop interactions that:
+
+- Send cross-channel notifications to email, SMS, in-app feeds, and workplace chat applications like Slack and MS Teams.
+- Power advanced cross-channel escalation flows to bubble up messages between channels or across team members.
+- Solicit structured input such as approve/reject buttons, or unstructured feedback in the form of text or prompt modifications.
+- Handle long-running async interactions that "interrupt" and "resume" your agent workflows.
+- Give full visibility into the messages sent from your AI agent workflows and track engagement of those messages across channels.
+
+## How Knock powers human-in-the-loop flows
+
+Knock uses [workflows](/concepts/workflows) to power human in the loop messaging across channels. Here's a high-level overview of how this works:
+
+1. You setup a workflow in the Knock dashboard that describes the message to send and the channels to send it to.
+2. Your agent calls to Knock to [trigger the workflow](/send-notifications/trigger-workflows/overview) with a set of recipients and any additional context for the request.
+3. Your user receives the message on the channel, which includes a the context for the request and a set of actions to take.
+4. The user then interacts with the message and the result is recorded back to Knock.
+5. Knock then triggers an [outbound webhook](/developer-tools/outbound-webhooks/overview) back to your agent application with the result of the interaction.
+6. Your agent application can then use the incoming interaction event from Knock to resume execution, or respond to the interaction.
+
+## Helper methods
+
+<Callout
+  emoji="💡"
+  text={
+    <>
+      <strong>Note</strong>: The following helper methods are only exposed for
+      the AI SDK. If you're using the Knock Agent toolkit with another Agent
+      framework and need to implement a custom flow, please reach out to us at{" "}
+      <a href="mailto:support@knock.app">support@knock.app</a>.
+    </>
+  }
+/>
+
+The Knock Agent Toolkit exposes a set of helper methods that you can use to power human-in-the-loop flows for common cases, and low-level primitives should you need to implement a custom flow.
+
+### `toolkit.requiresHumanInput`
+
+The `requiresHumanInput` helper method allows you to wrap a tool in requiring human input to proceed. When a tool is wrapped with this method, when the LLM tries to invoke the call it will instead delegate the tool call to Knock, passing the tool execution context to the Knock workflow.
+
+```typescript title="Wrap tool in requiring input"
+import { createToolkit } from "@knocklabs/agent-toolkit/ai-sdk";
+
+const toolkit = await createToolkit({
+  serviceToken: process.env.KNOCK_SERVICE_TOKEN,
+});
+
+const { classifyWork: classifyToolRequiringInput } = toolkit.requireHumanInput(
+  { classifyWork },
+  {
+    // (required) The key of the workflow to trigger
+    workflow: "approve-classification",
+    // (required) The list of recipients to trigger the workflow for
+    recipients: ["user_123"],
+    // (optional) Any additional data to pass along with the request
+    data: {},
+  },
+);
+```
+
+Calling `requireHumanInput` will return a new tool that you pass in place of the original tool in your model. When the LLM invokes the new tool, it will instead delegate the tool call to Knock, passing the tool execution context to the Knock workflow.
+
+Note: when the LLM invokes the new tool, it will appear as if the tool-call completed, albeit with a result that indicates that the tool is still waiting for human input. This is expected behavior.
+
+### `toolkit.handleMessageInteracted`
+
+The `handleMessageInteracted` helper method allows you to handle an incoming `message.interacted` event from Knock and determine if there's an interaction with the message that should be handled by your agent workflow.
+
+```typescript title="Handling an incoming interaction"
+import { createToolkit } from "@knocklabs/agent-toolkit/ai-sdk";
+
+const toolkit = await createToolkit({
+  serviceToken: process.env.KNOCK_SERVICE_TOKEN,
+});
+
+function handleIncomingInteraction(event) {
+  const interactionEvent = toolkit.handleMessageInteracted(event);
+
+  if (
+    interactionEvent &&
+    interactionEvent.workflow === "my-approval-workflow" &&
+    interactionEvent.interaction.action === "approved"
+  ) {
+    // Do something as a result of the approval
+  }
+}
+```
+
+### `toolkit.resumeToolExecution`
+
+The `resumeToolExecution` helper method allows you to resume tool execution after a human has interacted with the message and you have received an affirmative response to proceed.
+
+You pass the `resumeToolExecution` method the `DeferredToolCallInteractionResult` that you've received from Knock via the `handleMessageInteracted` method. Here's an example of how you might use this method:
+
+```typescript title="Resuming tool execution"
+import { createToolkit } from "@knocklabs/agent-toolkit/ai-sdk";
+
+const toolkit = await createToolkit({
+  serviceToken: process.env.KNOCK_SERVICE_TOKEN,
+});
+
+function handleIncomingInteraction(event) {
+  const interactionEvent = toolkit.handleMessageInteracted(event);
+
+  if (interactionEvent && interactionEvent.hasToolCall) {
+    const toolResult = await toolkit.resumeToolExecution(interactionEvent);
+    // Do something with the tool result
+  }
+}
+```
+
+When using the `resumeToolExecution` method, you must have first registered any tools that require human input using the `requiresHumanInput` method. This ensures that the toolkit has access to the necessary information to resume the tool execution.
+
+In the AI SDK, the `resumeToolExecution` method will return a tool status object where you can access the result under the `result` property. The original `toolCallId` is also included.
+
+## Example: In-app approval flow
+
+In this guide we show you how to setup an approval flow that sends an in-app notification to a notification feed requesting approval when the agent wishes to invoke a particular tool.
+
+<Steps>
+  <Step title="Setting up a workflow to power approvals">
+    To start, you'll want to setup a Knock workflow with a single, in-app feed channel step that sends an approval message to an in-app feed. You can find a workflow template for this in the [workflow templates repository](https://github.com/knocklabs/workflow-templates/blob/main/workflows/approval-workflow.json).
+  </Step>
+  <Step title="Handling the feed interaction">
+    Next, you'll need to add an interaction handler such that when a user taps on the approve/reject buttons in the notification feed that 
+  </Step>
+  <Step title="Setting up an outbound webhook in Knock">
+    A human in the loop interaction is inherently an asynchronous action, and so requires that we might need to handle the approval at some later point. Knock uses [outbound webhooks](/developer-tools/outbound-webhooks/overview) to forward your events to your application, helping to implement this asynchronous behavior.
+
+    To set up an outbound webhook, you'll need to create a new webhook under "Developers" > "Webhooks" in the Knock dashboard. Add a URL for your service and select the `message.interacted` event. You can read more about the available [event types in our guide](/developer-tools/outbound-webhooks/event-types).
path: content/developer-tools/agent-toolkit/human-in-the-loop-flows.mdx
user: login: rachael-t
body: ```suggestion
    To set up an outbound webhook, you'll need to create a new webhook under **Developers** > **Webhooks** in the Knock dashboard. Add a URL for your service and select the `message.interacted` event. You can read more about the available [event types in our guide](/developer-tools/outbound-webhooks/event-types).
```
created_at: 2025-04-23T18:17:05Z
author_association: CONTRIBUTOR
diff_hunk: @@ -0,0 +1,34 @@
+---
+title: Providing context to your Knock Agent Toolkit instance
+description: Learn how to configure the Knock Agent Toolkit to use context to aid with tool calls in your AI agent workflows.
+section: Developer tools
+---
+
+The Knock Agent Toolkit allows you to pass context on initialization to automatically scope requests to Knock. This is useful when you're interacting with a single logged in user, or you already know the organization that the agent is interacting with.
+
+## Available context
+
+- `userId`: The user ID of the user that the agent is interacting with.
+- `tenantId`: The tenant ID of the organization/workspace/account that the agent is interacting with.
+
+## Setting context
+
+You can set context on the `createToolkit` method.
+
+```typescript
+const toolkit = await createToolkit({
+  serviceToken: process.env.KNOCK_SERVICE_TOKEN,
+  userId: "user_123",
+  tenantId: "tenant_123",
+});
+```
+
+## Where context is used
+
+Once you've set the userId or tenantId context, it will be used to automatically scope requests to Knock. This means that you don't need to pass the userId or tenantId with every request, it will be set automatically.
path: content/developer-tools/agent-toolkit/providing-context.mdx
user: login: rachael-t
body: ```suggestion
Once you've set the `userId` or `tenantId` context, it will be used to automatically scope requests to Knock. This means that you don't need to pass the `userId` or `tenantId` with every request, it will be set automatically.
```
created_at: 2025-04-23T18:18:24Z
author_association: CONTRIBUTOR
diff_hunk: @@ -0,0 +1,139 @@
+---
+title: Model Context Protocol (MCP) Server
+description: Use the Knock MCP server to supercharge your Knock integration and make Knock accessible to LLMs and AI agents via tool calling.
path: content/developer-tools/mcp-server.mdx
user: login: samseely
body: ```suggestion
description: Use the Knock MCP server to make Knock accessible to LLMs and AI agents via tool calling.
```

I feel like better to just use super direct language here and drop marketing-y words like supercharge
created_at: 2025-04-24T14:36:56Z
author_association: CONTRIBUTOR
diff_hunk: @@ -0,0 +1,208 @@
+---
+title: Powering human-in-the-loop flows with the Knock Agent Toolkit
+description: Learn how to use the Knock Agent Toolkit within your AI agent workflows to power rich human-in-the-loop interactions.
+section: Developer tools
+---
+
+The Knock Agent Toolkit allows you to power rich human-in-the-loop interactions. For example, you can use the agent toolkit to create a workflow that lets a person to approve or reject work that the agent has done, powered by Knock's cross-channel messaging workflows.
+
+The Agent Toolkit exposes a set of helper methods that make it trivial for you to wrap your tool calls in requiring human input to proceed, and leveraging Knock's webhook mechanism to handle the asynchronous nature of a human-in-the-loop interaction. Knock takes care of all of the heavy lifting for you, making it easy to build rich human-in-the-loop flows with little effort.
path: content/developer-tools/agent-toolkit/human-in-the-loop-flows.mdx
user: login: JEverhart383
body: ```suggestion
The Agent Toolkit exposes a set of helper methods that wrap your tool calls in `requiresHumanInput` to proceed and leverage Knock's webhook mechanism to handle the asynchronous nature of a human-in-the-loop interaction. Knock takes care of all of the heavy lifting for you, making it easy to build rich human-in-the-loop flows with little effort.
```
maybe `requiresHumanInput` should be method name here
created_at: 2025-04-24T14:39:19Z
author_association: CONTRIBUTOR
diff_hunk: @@ -0,0 +1,208 @@
+---
+title: Powering human-in-the-loop flows with the Knock Agent Toolkit
+description: Learn how to use the Knock Agent Toolkit within your AI agent workflows to power rich human-in-the-loop interactions.
+section: Developer tools
+---
+
+The Knock Agent Toolkit allows you to power rich human-in-the-loop interactions. For example, you can use the agent toolkit to create a workflow that lets a person to approve or reject work that the agent has done, powered by Knock's cross-channel messaging workflows.
+
+The Agent Toolkit exposes a set of helper methods that make it trivial for you to wrap your tool calls in requiring human input to proceed, and leveraging Knock's webhook mechanism to handle the asynchronous nature of a human-in-the-loop interaction. Knock takes care of all of the heavy lifting for you, making it easy to build rich human-in-the-loop flows with little effort.
+
+Using Knock it's possible to power human-in-the-loop interactions that:
+
+- Send cross-channel notifications to email, SMS, in-app feeds, and workplace chat applications like Slack and MS Teams.
+- Power advanced cross-channel escalation flows to bubble up messages between channels or across team members.
+- Solicit structured input such as approve/reject buttons, or unstructured feedback in the form of text or prompt modifications.
+- Handle long-running async interactions that "interrupt" and "resume" your agent workflows.
+- Give full visibility into the messages sent from your AI agent workflows and track engagement of those messages across channels.
+
+## How Knock powers human-in-the-loop flows
+
+Knock uses [workflows](/concepts/workflows) to power human in the loop messaging across channels. Here's a high-level overview of how this works:
+
+1. You setup a workflow in the Knock dashboard that describes the message to send and the channels to send it to.
+2. Your agent calls to Knock to [trigger the workflow](/send-notifications/trigger-workflows/overview) with a set of recipients and any additional context for the request.
+3. Your user receives the message on the channel, which includes a the context for the request and a set of actions to take.
+4. The user then interacts with the message and the result is recorded back to Knock.
path: content/developer-tools/agent-toolkit/human-in-the-loop-flows.mdx
user: login: JEverhart383
body: ```suggestion
4. The user then interacts with the message and the result is sent back to Knock.
```
created_at: 2025-04-24T14:41:18Z
author_association: CONTRIBUTOR
diff_hunk: @@ -0,0 +1,208 @@
+---
+title: Powering human-in-the-loop flows with the Knock Agent Toolkit
+description: Learn how to use the Knock Agent Toolkit within your AI agent workflows to power rich human-in-the-loop interactions.
+section: Developer tools
+---
+
+The Knock Agent Toolkit allows you to power rich human-in-the-loop interactions. For example, you can use the agent toolkit to create a workflow that lets a person to approve or reject work that the agent has done, powered by Knock's cross-channel messaging workflows.
+
+The Agent Toolkit exposes a set of helper methods that make it trivial for you to wrap your tool calls in requiring human input to proceed, and leveraging Knock's webhook mechanism to handle the asynchronous nature of a human-in-the-loop interaction. Knock takes care of all of the heavy lifting for you, making it easy to build rich human-in-the-loop flows with little effort.
+
+Using Knock it's possible to power human-in-the-loop interactions that:
+
+- Send cross-channel notifications to email, SMS, in-app feeds, and workplace chat applications like Slack and MS Teams.
+- Power advanced cross-channel escalation flows to bubble up messages between channels or across team members.
+- Solicit structured input such as approve/reject buttons, or unstructured feedback in the form of text or prompt modifications.
+- Handle long-running async interactions that "interrupt" and "resume" your agent workflows.
+- Give full visibility into the messages sent from your AI agent workflows and track engagement of those messages across channels.
+
+## How Knock powers human-in-the-loop flows
+
+Knock uses [workflows](/concepts/workflows) to power human in the loop messaging across channels. Here's a high-level overview of how this works:
+
+1. You setup a workflow in the Knock dashboard that describes the message to send and the channels to send it to.
+2. Your agent calls to Knock to [trigger the workflow](/send-notifications/trigger-workflows/overview) with a set of recipients and any additional context for the request.
+3. Your user receives the message on the channel, which includes a the context for the request and a set of actions to take.
+4. The user then interacts with the message and the result is recorded back to Knock.
+5. Knock then triggers an [outbound webhook](/developer-tools/outbound-webhooks/overview) back to your agent application with the result of the interaction.
+6. Your agent application can then use the incoming interaction event from Knock to resume execution, or respond to the interaction.
+
+## Helper methods
+
+<Callout
+  emoji="💡"
+  text={
+    <>
+      <strong>Note</strong>: The following helper methods are only exposed for
+      the AI SDK. If you're using the Knock Agent toolkit with another Agent
+      framework and need to implement a custom flow, please reach out to us at{" "}
+      <a href="mailto:support@knock.app">support@knock.app</a>.
+    </>
+  }
+/>
+
+The Knock Agent Toolkit exposes a set of helper methods that you can use to power human-in-the-loop flows for common cases, and low-level primitives should you need to implement a custom flow.
+
+### `toolkit.requiresHumanInput`
+
+The `requiresHumanInput` helper method allows you to wrap a tool in requiring human input to proceed. When a tool is wrapped with this method, when the LLM tries to invoke the call it will instead delegate the tool call to Knock, passing the tool execution context to the Knock workflow.
+
+```typescript title="Wrap tool in requiring input"
+import { createToolkit } from "@knocklabs/agent-toolkit/ai-sdk";
+
+const toolkit = await createToolkit({
+  serviceToken: process.env.KNOCK_SERVICE_TOKEN,
+});
+
+const { classifyWork: classifyToolRequiringInput } = toolkit.requireHumanInput(
+  { classifyWork },
+  {
+    // (required) The key of the workflow to trigger
+    workflow: "approve-classification",
+    // (required) The list of recipients to trigger the workflow for
+    recipients: ["user_123"],
+    // (optional) Any additional data to pass along with the request
+    data: {},
+  },
+);
+```
+
+Calling `requireHumanInput` will return a new tool that you pass in place of the original tool in your model. When the LLM invokes the new tool, it will instead delegate the tool call to Knock, passing the tool execution context to the Knock workflow.
+
+Note: when the LLM invokes the new tool, it will appear as if the tool-call completed, albeit with a result that indicates that the tool is still waiting for human input. This is expected behavior.
path: content/developer-tools/agent-toolkit/human-in-the-loop-flows.mdx
user: login: JEverhart383
body: yeah, agreed - this was a confusing part of the process when I tried to roll my own version of this. If we can, maybe document the resulting message here so someone can handle it on their own
created_at: 2025-04-24T14:44:45Z
author_association: CONTRIBUTOR
diff_hunk: @@ -0,0 +1,208 @@
+---
+title: Powering human-in-the-loop flows with the Knock Agent Toolkit
+description: Learn how to use the Knock Agent Toolkit within your AI agent workflows to power rich human-in-the-loop interactions.
+section: Developer tools
+---
+
+The Knock Agent Toolkit allows you to power rich human-in-the-loop interactions. For example, you can use the agent toolkit to create a workflow that lets a person to approve or reject work that the agent has done, powered by Knock's cross-channel messaging workflows.
+
+The Agent Toolkit exposes a set of helper methods that make it trivial for you to wrap your tool calls in requiring human input to proceed, and leveraging Knock's webhook mechanism to handle the asynchronous nature of a human-in-the-loop interaction. Knock takes care of all of the heavy lifting for you, making it easy to build rich human-in-the-loop flows with little effort.
+
+Using Knock it's possible to power human-in-the-loop interactions that:
+
+- Send cross-channel notifications to email, SMS, in-app feeds, and workplace chat applications like Slack and MS Teams.
+- Power advanced cross-channel escalation flows to bubble up messages between channels or across team members.
+- Solicit structured input such as approve/reject buttons, or unstructured feedback in the form of text or prompt modifications.
+- Handle long-running async interactions that "interrupt" and "resume" your agent workflows.
+- Give full visibility into the messages sent from your AI agent workflows and track engagement of those messages across channels.
+
+## How Knock powers human-in-the-loop flows
+
+Knock uses [workflows](/concepts/workflows) to power human in the loop messaging across channels. Here's a high-level overview of how this works:
+
+1. You setup a workflow in the Knock dashboard that describes the message to send and the channels to send it to.
+2. Your agent calls to Knock to [trigger the workflow](/send-notifications/trigger-workflows/overview) with a set of recipients and any additional context for the request.
+3. Your user receives the message on the channel, which includes a the context for the request and a set of actions to take.
+4. The user then interacts with the message and the result is recorded back to Knock.
+5. Knock then triggers an [outbound webhook](/developer-tools/outbound-webhooks/overview) back to your agent application with the result of the interaction.
+6. Your agent application can then use the incoming interaction event from Knock to resume execution, or respond to the interaction.
+
+## Helper methods
+
+<Callout
+  emoji="💡"
+  text={
+    <>
+      <strong>Note</strong>: The following helper methods are only exposed for
+      the AI SDK. If you're using the Knock Agent toolkit with another Agent
+      framework and need to implement a custom flow, please reach out to us at{" "}
+      <a href="mailto:support@knock.app">support@knock.app</a>.
+    </>
+  }
+/>
+
+The Knock Agent Toolkit exposes a set of helper methods that you can use to power human-in-the-loop flows for common cases, and low-level primitives should you need to implement a custom flow.
+
+### `toolkit.requiresHumanInput`
+
+The `requiresHumanInput` helper method allows you to wrap a tool in requiring human input to proceed. When a tool is wrapped with this method, when the LLM tries to invoke the call it will instead delegate the tool call to Knock, passing the tool execution context to the Knock workflow.
+
+```typescript title="Wrap tool in requiring input"
+import { createToolkit } from "@knocklabs/agent-toolkit/ai-sdk";
+
+const toolkit = await createToolkit({
+  serviceToken: process.env.KNOCK_SERVICE_TOKEN,
+});
+
+const { classifyWork: classifyToolRequiringInput } = toolkit.requireHumanInput(
+  { classifyWork },
+  {
+    // (required) The key of the workflow to trigger
+    workflow: "approve-classification",
+    // (required) The list of recipients to trigger the workflow for
+    recipients: ["user_123"],
+    // (optional) Any additional data to pass along with the request
+    data: {},
+  },
+);
+```
+
+Calling `requireHumanInput` will return a new tool that you pass in place of the original tool in your model. When the LLM invokes the new tool, it will instead delegate the tool call to Knock, passing the tool execution context to the Knock workflow.
+
+Note: when the LLM invokes the new tool, it will appear as if the tool-call completed, albeit with a result that indicates that the tool is still waiting for human input. This is expected behavior.
path: content/developer-tools/agent-toolkit/human-in-the-loop-flows.mdx
user: login: samseely
body: yep agreed we should
created_at: 2025-04-24T15:20:07Z
author_association: CONTRIBUTOR
diff_hunk: @@ -0,0 +1,96 @@
+---
+title: Agent toolkit
+description: Use Knock's agent toolkit to give your AI agents the ability to send cross-channel messaging and power rich human-in-the-loop flows.
+section: Developer tools
+---
+
+The Knock agent toolkit exposes a set of tools that your AI agent applications can use to interact with Knock via function calling. Using the Knock agent toolkit, you can:
+
+- Give your AI agent applications the ability to [send cross-channel notifications](/developer-tools/agent-toolkit/workflows-as-tools) to your users.
+- Power rich [human-in-the-loop flows](/developer-tools/agent-toolkit/human-in-the-loop-flows) that allow your agents to solicit structured input from users, or require human approval of actions taken by your agents.
+- Let your agents create and manage resources within your Knock account.
+
+<Callout
+  emoji="💡"
+  text={
+    <>
+      The Knock agent toolkit is currently in beta as a TypeScript package only.
+      We're considering adding support for Python too. If you're interested in
+      using the Knock agent toolkit in another language, please let us know at{" "}
+      <a href="mailto:support@knock.app">support@knock.app</a>.
+    </>
+  }
+/>
+
+## Workflows-as-tools
+
+By default the agent toolkit will expose each of your workflows as a tool that your agents can invoke to power cross-channel messaging. If you have a workflow (`comment-created`) within your Knock account, the agent toolkit will expose a `trigger_comment_created_workflow` tool that your agents can invoke to send a notification.
+
+Each tool describes the parameters that are required to trigger the workflow, where the parameters for the data payload are read from the [workflow's trigger data JSON schema](/developer-tools/validating-trigger-data). Adding the JSON schema for your workflow trigger data allows the LLM to understand the exact shape and definition of the data payload for the workflow.
+
+If the workflow does not specify a trigger data JSON schema, the tool will define a generic data payload for the AI agent to fill in.
+
+You can control this behavior by either:
+
+- Disabling entirely by setting `workflows.read` to `false`
+- Specifying a list of workflow keys that are allowed to be exposed to the agent (`workflows.read = ["comment-created"]`)
+
+Read more about [exposing workflows as tools](/developer-tools/agent-toolkit/workflows-as-tools).
+
+## Human-in-the-loop flows
+
+You can use the agent toolkit to power rich human-in-the-loop interactions.
+
+For example, you can use the agent toolkit to create a workflow that allows a person to approve or reject the agent's work, where the approval is an actionable notification sent by Knock.
+
+The toolkit exposes wrappers for requiring asynchronous human input. When wrapped, your tools will first delegate to Knock to trigger a workflow that you define, then asynchronously continue tool execution once you have received a response from a human.
+
+```typescript title="Wrapping a tool as requiring human input"
+import { createToolkit } from "@knocklabs/agent-toolkit/ai-sdk";
+
+const toolkit = createToolkit({
+  serviceToken: process.env.KNOCK_SERVICE_TOKEN,
+});
+
+const classifyToolRequiringInput = toolkit.requireHumanInput(classifyWork, {
+  workflow: "approve-classification",
+  recipients: ["user_123"],
+});
+```
+
+You can read more about [powering human-in-the-loop flows in the guide](/developer-tools/agent-toolkit/human-in-the-loop-flows).
+
+## Creating Knock resources
+
+You can create Knock resources using the agent toolkit through function calling.
+
+For example, you may want an agent to create or update a user's record in Knock as part of your agent workflow, or subscribe a user to another object so they can receive notifications later.
+
+The agent toolkit exposes most common Knock resources as tools that your agents can invoke. You can see the list of available tools in the [package documentation](https://github.com/knocklabs/agent-toolkit).
path: content/developer-tools/agent-toolkit/overview.mdx
user: login: samseely
body: Do we need the last sentence here given paragraph below this?
```suggestion
The agent toolkit exposes most common Knock resources as tools that your agents can invoke.
```
created_at: 2025-04-25T01:31:07Z
author_association: CONTRIBUTOR
diff_hunk: @@ -0,0 +1,151 @@
+---
+title: Getting started with the Knock agent toolkit
+description: Learn how to use the Knock agent toolkit within your AI agent workflows to power cross-channel messaging and rich human-in-the-loop interactions.
+section: Developer tools
+---
+
+## Installing the Knock agent toolkit
+
+You can install the Knock agent toolkit using npm, yarn, or pnpm.
+
+```bash
+npm install @knocklabs/agent-toolkit
+```
+
+Once installed you can use the toolkit through the exposed SDK adapters, or if you need low-level access to the toolkit you can use the `@knocklabs/agent-toolkit` package directly.
+
+## Setting up your .env file
+
+You'll need to have a [service token](/developer-tools/service-tokens) setup on your Knock account to authenticate with the Knock Agent Toolkit.
+
+```bash
+KNOCK_SERVICE_TOKEN=st_1234567890
+```
+
+## Usage with the Vercel AI SDK
+
+```typescript title="Usage with the Vercel AI SDK"
+import { createToolkit } from "@knocklabs/agent-toolkit/ai-sdk";
+
+const toolkit = await createKnockToolkit({
+  serviceToken: process.env.KNOCK_SERVICE_TOKEN!,
+  permissions: {
+    users: { manage: true },
+  },
+});
+
+const result = await generateText({
+  model: openai("gpt-4o"),
+  tools: {
+    ...toolkit.getTools("users"),
+  },
+  maxSteps: 5,
+  prompt:
+    "Update the current user's profile with information about them, knowing that they are Alan Grant from Jurassic Park. Include custom properties about their favorite dinosaur.",
+});
+```
+
+## Usage with the OpenAI SDK
+
+```typescript title="Usage with the OpenAI SDK"
+import OpenAI from "openai";
+import { createToolkit } from "@knocklabs/agent-toolkit/openai";
+
+const toolkit = await createToolkit({
+  serviceToken: process.env.KNOCK_SERVICE_TOKEN!,
+});
+
+const openai = new OpenAI({
+  apiKey: process.env.OPENAI_API_KEY!,
+});
+
+const messages = [
+  {
+    role: "user",
+    content:
+      "Update the current user's profile with information about them, knowing that they are Alan Grant from Jurassic Park. Include custom properties about their favorite dinosaur.",
+  },
+];
+
+(async (): Promise<void> => {
+  const result = await openai.chat.completions.create({
+    model: "gpt-4o",
+    messages,
+  });
+
+  while (true) {
+    // eslint-disable-next-line no-await-in-loop
+    const completion = await openai.chat.completions.create({
+      model: "gpt-4o",
+      messages,
+      tools: toolkit.getTools("users"),
+    });
+
+    const message = completion.choices[0].message;
+
+    messages.push(message);
+
+    if (message.tool_calls) {
+      // eslint-disable-next-line no-await-in-loop
+      const toolMessages = await Promise.all(
+        message.tool_calls.map((tc) => toolkit.handleToolCall(tc)),
+      );
+      messages = [...messages, ...toolMessages];
+    } else {
+      console.log(completion.choices[0].message);
+      break;
+    }
+  }
+})();
+```
+
+## Usage with the LangChain framework
+
+```typescript title="Usage with the LangChain framework"
+import { createToolkit } from "@knocklabs/agent-toolkit/langchain";
+import { ChatOpenAI } from "@langchain/openai";
+import type { ChatPromptTemplate } from "@langchain/core/prompts";
+import { pull } from "langchain/hub";
+import { AgentExecutor, createStructuredChatAgent } from "langchain/agents";
+
+const toolkit = await createToolkit({
+  serviceToken: process.env.KNOCK_SERVICE_TOKEN!,
+});
+
+const llm = new ChatOpenAI({
+  model: "gpt-4o",
+});
+
+(async (): Promise<void> => {
+  const prompt = await pull<ChatPromptTemplate>(
+    "hwchase17/structured-chat-agent",
+  );
+
+  const tools = toolkit.getTools("users");
+
+  const agent = await createStructuredChatAgent({
+    llm,
+    tools,
+    prompt,
+  });
+
+  const agentExecutor = new AgentExecutor({
+    agent,
+    tools,
+  });
+
+  const response = await agentExecutor.invoke({
+    input:
+      "Update the user's profile with information about them, knowing that they are Alan Grant from Jurassic Park. Include custom properties about their favorite dinosaur.",
+  });
+
+  console.log(response);
+})();
+```
+
+## See also
path: content/developer-tools/agent-toolkit/getting-started.mdx
user: login: samseely
body: Let's call this "Relevant links". "See also" in table of contents on right looks weird
created_at: 2025-04-25T01:31:54Z
author_association: CONTRIBUTOR
diff_hunk: @@ -0,0 +1,96 @@
+---
+title: Agent toolkit
+description: Use Knock's agent toolkit to give your AI agents the ability to send cross-channel messaging and power rich human-in-the-loop flows.
+section: Developer tools
+---
+
+The Knock agent toolkit exposes a set of tools that your AI agent applications can use to interact with Knock via function calling. Using the Knock agent toolkit, you can:
+
+- Give your AI agent applications the ability to [send cross-channel notifications](/developer-tools/agent-toolkit/workflows-as-tools) to your users.
+- Power rich [human-in-the-loop flows](/developer-tools/agent-toolkit/human-in-the-loop-flows) that allow your agents to solicit structured input from users, or require human approval of actions taken by your agents.
+- Let your agents create and manage resources within your Knock account.
+
+<Callout
+  emoji="💡"
+  text={
+    <>
+      The Knock agent toolkit is currently in beta as a TypeScript package only.
+      We're considering adding support for Python too. If you're interested in
+      using the Knock agent toolkit in another language, please let us know at{" "}
+      <a href="mailto:support@knock.app">support@knock.app</a>.
+    </>
+  }
+/>
+
+## Workflows-as-tools
+
+By default the agent toolkit will expose each of your workflows as a tool that your agents can invoke to power cross-channel messaging. If you have a workflow (`comment-created`) within your Knock account, the agent toolkit will expose a `trigger_comment_created_workflow` tool that your agents can invoke to send a notification.
+
+Each tool describes the parameters that are required to trigger the workflow, where the parameters for the data payload are read from the [workflow's trigger data JSON schema](/developer-tools/validating-trigger-data). Adding the JSON schema for your workflow trigger data allows the LLM to understand the exact shape and definition of the data payload for the workflow.
+
+If the workflow does not specify a trigger data JSON schema, the tool will define a generic data payload for the AI agent to fill in.
+
+You can control this behavior by either:
+
+- Disabling entirely by setting `workflows.read` to `false`
+- Specifying a list of workflow keys that are allowed to be exposed to the agent (`workflows.read = ["comment-created"]`)
+
+Read more about [exposing workflows as tools](/developer-tools/agent-toolkit/workflows-as-tools).
+
+## Human-in-the-loop flows
+
+You can use the agent toolkit to power rich human-in-the-loop interactions.
+
+For example, you can use the agent toolkit to create a workflow that allows a person to approve or reject the agent's work, where the approval is an actionable notification sent by Knock.
+
+The toolkit exposes wrappers for requiring asynchronous human input. When wrapped, your tools will first delegate to Knock to trigger a workflow that you define, then asynchronously continue tool execution once you have received a response from a human.
+
+```typescript title="Wrapping a tool as requiring human input"
+import { createToolkit } from "@knocklabs/agent-toolkit/ai-sdk";
+
+const toolkit = createToolkit({
+  serviceToken: process.env.KNOCK_SERVICE_TOKEN,
+});
+
+const classifyToolRequiringInput = toolkit.requireHumanInput(classifyWork, {
+  workflow: "approve-classification",
+  recipients: ["user_123"],
+});
+```
+
+You can read more about [powering human-in-the-loop flows in the guide](/developer-tools/agent-toolkit/human-in-the-loop-flows).
+
+## Creating Knock resources
+
+You can create Knock resources using the agent toolkit through function calling.
+
+For example, you may want an agent to create or update a user's record in Knock as part of your agent workflow, or subscribe a user to another object so they can receive notifications later.
+
+The agent toolkit exposes most common Knock resources as tools that your agents can invoke. You can see the list of available tools in the [package documentation](https://github.com/knocklabs/agent-toolkit).
+
+You can find the list of available tools in the [tools reference](/developer-tools/agent-toolkit/tools-reference).
+
+## Security and authorization
+
+To authenticate with the Knock agent toolkit, you need to provide a [service token](/developer-tools/service-tokens) for your Knock account. This token should be kept secret and not exposed to the LLM. Your service token grants access to all of your Knock resources, so it's important to keep it secure.
+
+You can also customize the tools exposed to the AI Agent by specifying a set of permissions that define the resources that the agent has access to.
+
+For example, the following permissions will expose only the `users` resource to the agent, which will include the ability to read and manage users.
+
+```typescript title="Setting permissions for the agent"
+{
+  permissions: {
+    users: {
+      read: true,
+      manage: true
+    },
+  },
+};
+```
+
+## See also
path: content/developer-tools/agent-toolkit/overview.mdx
user: login: samseely
body: ```suggestion
## Relevant links
```
created_at: 2025-04-25T01:32:12Z
author_association: CONTRIBUTOR

PR comments:
user: login: linear[bot]
created_at: 2025-04-22T14:58:04Z
body: <p><a href="https://linear.app/knock/issue/KNO-8425/[docs]-add-agent-toolkit-docs">KNO-8425 [Docs] Add agent toolkit docs</a></p>
author_association: NONE
user: login: vercel[bot]
created_at: 2025-04-22T14:58:07Z
body: [vc]: #MmzuPG7DFY8vVctoYjm6WmlWt8qbyhhiAtOBg2ibpT8=:eyJpc01vbm9yZXBvIjp0cnVlLCJ0eXBlIjoiZ2l0aHViIiwicHJvamVjdHMiOlt7Im5hbWUiOiJkb2NzIiwiaW5zcGVjdG9yVXJsIjoiaHR0cHM6Ly92ZXJjZWwuY29tL2tub2NrbGFicy9kb2NzLzJrdTd5UW03eExrdVlLS1lUa1JpVzlQVzNyM0YiLCJwcmV2aWV3VXJsIjoiZG9jcy1naXQtY2piZWxsLWtuby04NDI1LWRvY3MtYWRkLWFnZW50LXRvb2xraXQtZG9jcy1rbm9ja2xhYnMudmVyY2VsLmFwcCIsIm5leHRDb21taXRTdGF0dXMiOiJERVBMT1lFRCIsImxpdmVGZWVkYmFjayI6eyJyZXNvbHZlZCI6MCwidW5yZXNvbHZlZCI6MCwidG90YWwiOjAsImxpbmsiOiJkb2NzLWdpdC1jamJlbGwta25vLTg0MjUtZG9jcy1hZGQtYWdlbnQtdG9vbGtpdC1kb2NzLWtub2NrbGFicy52ZXJjZWwuYXBwIn0sInJvb3REaXJlY3RvcnkiOm51bGx9XX0=
**The latest updates on your projects**. Learn more about [Vercel for Git ↗︎](https://vercel.link/github-learn-more)

| Name | Status | Preview | Comments | Updated (UTC) |
| :--- | :----- | :------ | :------- | :------ |
| **docs** | ✅ Ready ([Inspect](https://vercel.com/knocklabs/docs/2ku7yQm7xLkuYKKYTkRiW9PW3r3F)) | [Visit Preview](https://docs-git-cjbell-kno-8425-docs-add-agent-toolkit-docs-knocklabs.vercel.app) | 💬 [**Add feedback**](https://vercel.live/open-feedback/docs-git-cjbell-kno-8425-docs-add-agent-toolkit-docs-knocklabs.vercel.app?via=pr-comment-feedback-link) | Apr 25, 2025 2:48am |


author_association: NONE
user: login: JEverhart383
created_at: 2025-04-24T14:59:46Z
body: Are we still planning on including the 'copy as md' and 'open as MD' buttons on each page? Looking in profound, I think we need to try to make the llms.txt stuff as easy to discover as possible for the models to use it.
author_association: CONTRIBUTOR
user: login: cjbell
created_at: 2025-04-25T00:40:18Z
body: OK updates done @samseely @rachael-t @JEverhart383 🫡 

I think this is ready for another review.

@samseely I added a new `/tools-reference` that documents all of the tools we have available (all 39!)
author_association: CONTRIBUTOR