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

# Build an agent with MCP tools

> Create a saved agent that calls a vault-managed MCP server with encrypted per-end-user credentials.

Use the Agents API with MCP Vault when you want reusable agents that can call tools from an external MCP server.
The vault keeps MCP server configuration and credentials outside the agent definition, so your app can rotate credentials without editing every agent.

API Reference:

* [Agents collection and run endpoints](/api-reference/agents/create-an-agent)
* [MCP Vault server endpoints](/api-reference/mcp-vault/create-mcp-server)
* [MCP credential endpoints](/api-reference/mcp-vault/create-mcp-credential)

## 1. Register the MCP server

Create the MCP server once for the integration you want the agent to use.
Use `allowed_tools` to expose only the tools the agent needs.
Use `require_approval` when your product should ask the end user before the MCP tool runs.

<CodeGroup>
  ```bash CLI theme={null}
  mka1 llm mcp-vault create-server --body '{
    "name": "Linear",
    "server_label": "linear",
    "server_url": "https://mcp.linear.app/mcp",
    "server_description": "Access Linear issues, projects, and comments.",
    "allowed_tools": ["issues.list", "issues.create", "comments.create"],
    "require_approval": "always",
    "metadata": {
      "integration": "linear"
    }
  }' \
    -H 'X-On-Behalf-Of: <end-user-id>'
  ```

  ```ts MKA1 SDK theme={null}
  import { SDK } from "@meetkai/mka1";

  const sdk = new SDK({
    bearerAuth: "Bearer <mka1-api-key>",
  });

  const server = await sdk.llm.mcpVault.createServer({
    xOnBehalfOf: "<end-user-id>", // optional — attribute the request to one of your end users
    createMcpServerRequest: {
      name: "Linear",
      serverLabel: "linear",
      serverUrl: "https://mcp.linear.app/mcp",
      serverDescription: "Access Linear issues, projects, and comments.",
      allowedTools: ["issues.list", "issues.create", "comments.create"],
      requireApproval: "always",
      metadata: {
        integration: "linear",
      },
    },
  });

  console.log(server.id);
  ```

  ```ts fetch theme={null}
  const serverResponse = await fetch("https://apigw.mka1.com/api/v1/llm/mcp/servers", {
    method: "POST",
    headers: {
      "Content-Type": "application/json",
      Authorization: "Bearer <mka1-api-key>",
      "X-On-Behalf-Of": "<end-user-id>",
    },
    body: JSON.stringify({
      name: "Linear",
      server_label: "linear",
      server_url: "https://mcp.linear.app/mcp",
      server_description: "Access Linear issues, projects, and comments.",
      allowed_tools: ["issues.list", "issues.create", "comments.create"],
      require_approval: "always",
      metadata: {
        integration: "linear",
      },
    }),
  });

  const server = await serverResponse.json();
  console.log(server.id);
  ```

  ```bash bash theme={null}
  curl https://apigw.mka1.com/api/v1/llm/mcp/servers \
    --request POST \
    --header 'Content-Type: application/json' \
    --header 'Authorization: Bearer <mka1-api-key>' \
    --header 'X-On-Behalf-Of: <end-user-id>' \
    --data '{
      "name": "Linear",
      "server_label": "linear",
      "server_url": "https://mcp.linear.app/mcp",
      "server_description": "Access Linear issues, projects, and comments.",
      "allowed_tools": ["issues.list", "issues.create", "comments.create"],
      "require_approval": "always",
      "metadata": {
        "integration": "linear"
      }
    }'
  ```
</CodeGroup>

The response includes a stable MCP server ID such as `mcp_srv_...`.
Use that ID in agent tool definitions.
See the [Create MCP server API reference](/api-reference/mcp-vault/create-mcp-server) for the complete schema.

## 2. Store the MCP credential

Create a credential under the MCP server.
The credential can use a bearer token, an authorization header value, custom headers, or no auth.
Store end-user credentials with `X-On-Behalf-Of` so each end user gets isolated access.

<CodeGroup>
  ```bash CLI theme={null}
  mka1 llm mcp-vault create-credential \
    --server-id mcp_srv_123 \
    --body '{
      "name": "Personal Linear token",
      "auth_type": "bearer",
      "bearer_token": "<linear-api-key>"
    }' \
    -H 'X-On-Behalf-Of: <end-user-id>'
  ```

  ```ts MKA1 SDK theme={null}
  const credential = await sdk.llm.mcpVault.createCredential({
    serverId: "mcp_srv_123",
    xOnBehalfOf: "<end-user-id>",
    createMcpCredentialRequest: {
      name: "Personal Linear token",
      authType: "bearer",
      bearerToken: "<linear-api-key>",
    },
  });

  console.log(credential.id);
  ```

  ```ts fetch theme={null}
  const credentialResponse = await fetch(
    "https://apigw.mka1.com/api/v1/llm/mcp/servers/mcp_srv_123/credentials",
    {
      method: "POST",
      headers: {
        "Content-Type": "application/json",
        Authorization: "Bearer <mka1-api-key>",
        "X-On-Behalf-Of": "<end-user-id>",
      },
      body: JSON.stringify({
        name: "Personal Linear token",
        auth_type: "bearer",
        bearer_token: "<linear-api-key>",
      }),
    },
  );

  const credential = await credentialResponse.json();
  console.log(credential.id);
  ```

  ```bash bash theme={null}
  curl https://apigw.mka1.com/api/v1/llm/mcp/servers/mcp_srv_123/credentials \
    --request POST \
    --header 'Content-Type: application/json' \
    --header 'Authorization: Bearer <mka1-api-key>' \
    --header 'X-On-Behalf-Of: <end-user-id>' \
    --data '{
      "name": "Personal Linear token",
      "auth_type": "bearer",
      "bearer_token": "<linear-api-key>"
    }'
  ```
</CodeGroup>

The response includes a credential ID such as `mcp_cred_...`.
Secret values are stored by the vault and are not returned in later list responses.
Use [List MCP credentials](/api-reference/mcp-vault/list-mcp-credentials) when your app needs to show saved credential metadata.

## 3. Test the server

Test the server before you attach it to an agent.
This catches bad URLs and tool discovery problems early.
The response reports whether the server connected and which tools were discovered.

<CodeGroup>
  ```bash CLI theme={null}
  mka1 llm mcp-vault test-server \
    --server-id mcp_srv_123 \
    -H 'X-On-Behalf-Of: <end-user-id>'
  ```

  ```ts MKA1 SDK theme={null}
  const test = await sdk.llm.mcpVault.testServer({
    serverId: "mcp_srv_123",
    xOnBehalfOf: "<end-user-id>",
  });

  console.log(test);
  ```

  ```ts fetch theme={null}
  const testResponse = await fetch(
    "https://apigw.mka1.com/api/v1/llm/mcp/servers/mcp_srv_123/test",
    {
      method: "POST",
      headers: {
        Authorization: "Bearer <mka1-api-key>",
        "X-On-Behalf-Of": "<end-user-id>",
      },
    },
  );

  const test = await testResponse.json();
  console.log(test);
  ```

  ```bash bash theme={null}
  curl https://apigw.mka1.com/api/v1/llm/mcp/servers/mcp_srv_123/test \
    --request POST \
    --header 'Authorization: Bearer <mka1-api-key>' \
    --header 'X-On-Behalf-Of: <end-user-id>'
  ```
</CodeGroup>

See the [Test MCP server API reference](/api-reference/mcp-vault/test-mcp-server) for request and response details.

## 4. Create the agent

Add an MCP tool to the agent with `type: "mcp"`.
Reference the vault records with `mcp_server_id` and `mcp_credential_id`.
You can narrow the agent's access further with `allowed_tools` on the tool definition.

<CodeGroup>
  ```bash CLI theme={null}
  mka1 agents create --body '{
    "name": "linear-triage-agent",
    "description": "Triages Linear issues and drafts updates.",
    "model": "auto",
    "instructions": "Use Linear through MCP when the user asks about issue triage. Confirm before creating or editing external records.",
    "tools": [
      {
        "type": "mcp",
        "mcp_server_id": "mcp_srv_123",
        "mcp_credential_id": "mcp_cred_123",
        "allowed_tools": ["issues.list", "comments.create"],
        "require_approval": "always"
      }
    ],
    "tool_choice": "auto",
    "parallel_tool_calls": true,
    "metadata": {
      "team": "support"
    }
  }' \
    -H 'X-On-Behalf-Of: <end-user-id>'
  ```

  ```ts MKA1 SDK theme={null}
  const agent = await sdk.agents.createAgent({
    xOnBehalfOf: "<end-user-id>",
    createAgentRequest: {
      name: "linear-triage-agent",
      description: "Triages Linear issues and drafts updates.",
      model: "auto",
      instructions:
        "Use Linear through MCP when the user asks about issue triage. Confirm before creating or editing external records.",
      tools: [
        {
          type: "mcp",
          mcpServerId: "mcp_srv_123",
          mcpCredentialId: "mcp_cred_123",
          allowedTools: ["issues.list", "comments.create"],
          requireApproval: "always",
        },
      ],
      toolChoice: "auto",
      parallelToolCalls: true,
      metadata: {
        team: "support",
      },
    },
  });

  console.log(agent.id);
  ```

  ```ts fetch theme={null}
  const agentResponse = await fetch("https://apigw.mka1.com/api/v1/agents", {
    method: "POST",
    headers: {
      "Content-Type": "application/json",
      Authorization: "Bearer <mka1-api-key>",
      "X-On-Behalf-Of": "<end-user-id>",
    },
    body: JSON.stringify({
      name: "linear-triage-agent",
      description: "Triages Linear issues and drafts updates.",
      model: "auto",
      instructions:
        "Use Linear through MCP when the user asks about issue triage. Confirm before creating or editing external records.",
      tools: [
        {
          type: "mcp",
          mcp_server_id: "mcp_srv_123",
          mcp_credential_id: "mcp_cred_123",
          allowed_tools: ["issues.list", "comments.create"],
          require_approval: "always",
        },
      ],
      tool_choice: "auto",
      parallel_tool_calls: true,
      metadata: {
        team: "support",
      },
    }),
  });

  const agent = await agentResponse.json();
  console.log(agent.id);
  ```

  ```bash bash theme={null}
  curl https://apigw.mka1.com/api/v1/agents \
    --request POST \
    --header 'Content-Type: application/json' \
    --header 'Authorization: Bearer <mka1-api-key>' \
    --header 'X-On-Behalf-Of: <end-user-id>' \
    --data '{
      "name": "linear-triage-agent",
      "description": "Triages Linear issues and drafts updates.",
      "model": "auto",
      "instructions": "Use Linear through MCP when the user asks about issue triage. Confirm before creating or editing external records.",
      "tools": [
        {
          "type": "mcp",
          "mcp_server_id": "mcp_srv_123",
          "mcp_credential_id": "mcp_cred_123",
          "allowed_tools": ["issues.list", "comments.create"],
          "require_approval": "always"
        }
      ],
      "tool_choice": "auto",
      "parallel_tool_calls": true,
      "metadata": {
        "team": "support"
      }
    }'
  ```
</CodeGroup>

See the [Create an agent API reference](/api-reference/agents/create-an-agent) for every saved agent field.

## 5. Run the agent

Run the saved agent with the task-specific input.
The agent reuses the saved MCP configuration and credential reference.

<CodeGroup>
  ```bash CLI theme={null}
  mka1 agent-runs create \
    --agent-id agt_123 \
    --body '{
      "input": "Find my five newest bug issues and draft a short triage summary.",
      "metadata": {
        "source": "docs-recipe"
      }
    }' \
    -H 'X-On-Behalf-Of: <end-user-id>'
  ```

  ```ts MKA1 SDK theme={null}
  const run = await sdk.agentRuns.createAgentRun({
    agentId: "agt_123",
    xOnBehalfOf: "<end-user-id>",
    createAgentRunRequest: {
      input: "Find my five newest bug issues and draft a short triage summary.",
      metadata: {
        source: "docs-recipe",
      },
    },
  });

  console.log(run.id);
  ```

  ```ts fetch theme={null}
  const runResponse = await fetch("https://apigw.mka1.com/api/v1/agents/agt_123/runs", {
    method: "POST",
    headers: {
      "Content-Type": "application/json",
      Authorization: "Bearer <mka1-api-key>",
      "X-On-Behalf-Of": "<end-user-id>",
    },
    body: JSON.stringify({
      input: "Find my five newest bug issues and draft a short triage summary.",
      metadata: {
        source: "docs-recipe",
      },
    }),
  });

  const run = await runResponse.json();
  console.log(run.id);
  ```

  ```bash bash theme={null}
  curl https://apigw.mka1.com/api/v1/agents/agt_123/runs \
    --request POST \
    --header 'Content-Type: application/json' \
    --header 'Authorization: Bearer <mka1-api-key>' \
    --header 'X-On-Behalf-Of: <end-user-id>' \
    --data '{
      "input": "Find my five newest bug issues and draft a short triage summary.",
      "metadata": {
        "source": "docs-recipe"
      }
    }'
  ```
</CodeGroup>

Use [Retrieve an agent run](/api-reference/agent-runs/retrieve-an-agent-run) to poll status.
Use [Stream agent run events](/api-reference/agent-runs/stream-agent-run-events) when your UI should show tool calls and partial progress.

## Operational notes

* Keep server-level `allowed_tools` broad enough for the integration and tool-level `allowed_tools` as narrow as the agent's job allows.
* Prefer `require_approval: "always"` for tools that mutate external systems.
* Rotate a credential by creating a new MCP credential and updating the agent's MCP tool to reference the new `mcp_credential_id`.
* Delete credentials with the [Delete MCP credential endpoint](/api-reference/mcp-vault/delete-mcp-credential) when an end user disconnects an integration.
