# Quickstart: govern a local MCP tool

Wrap a harmless echo server and verify tool allow, block, and approval in Claude Desktop.

Updated: 2026-09-22

Canonical: https://docs.kastra.ai/start/local-mcp

## Prepare an isolated example

This walkthrough uses Claude Desktop on macOS, Python 3, the [Edge bundle](https://docs.kastra.ai/edge/install), and the [operator CLI](https://docs.kastra.ai/reference/cli). You need custom policy and approval access, an administrator, and an authorized approver. For another compatible host, use the gateway command shape in [local MCP setup](https://docs.kastra.ai/mcp/local-gateway).

The sample server has one tool, `docs_echo`, which returns text. It does not read or modify files, run shell commands, or call a network service. Download [echo-mcp.py](https://docs.kastra.ai/examples/echo-mcp.py), inspect it, and save it in a directory you will keep for the exercise.

```sh
curl --fail --output echo-mcp.py https://docs.kastra.ai/examples/echo-mcp.py
command -v python3
pwd
kastra auth login
kastra env create docs-mcp
kastra-edge config show
kastra-edge config set default_environment docs-mcp
```

Record the previous Edge environment. If `docs-mcp` already exists, choose a fresh environment and update the example policy's `metadata.environment`. Confirm enforcement mode in the console.

## Connect the echo server

In Claude Desktop's developer settings, edit its MCP configuration. Add this named entry under `mcpServers`, preserving any existing entries. Replace both paths with the absolute paths from your machine; JSON does not expand `~` or shell variables.

```json
{
  "mcpServers": {
    "kastra-docs-echo": {
      "command": "/ABSOLUTE/PATH/TO/python3",
      "args": ["/ABSOLUTE/PATH/TO/echo-mcp.py"]
    }
  }
}
```

Fully quit and restart Claude Desktop. Verify that `docs_echo` appears. This confirms the sample server works; it is not yet governed.

## Wrap it and activate the test policy

```sh
kastra-edge wrap-claude-desktop --dry-run --server kastra-docs-echo
kastra-edge wrap-claude-desktop --server kastra-docs-echo
curl --fail --output local-mcp.kastra https://docs.kastra.ai/examples/local-mcp.kastra
kastra policy validate local-mcp.kastra
kastra policy add local-mcp.kastra --activate
```

Inspect [local-mcp.kastra](https://docs.kastra.ai/examples/local-mcp.kastra) before applying it. It matches server `kastra-docs-echo`, tool `docs_echo`, and the argument marker `kastra-docs-deny` or `kastra-docs-hold`. Other calls default to ALLOW. HOLD expires after five minutes with denial.

Save the new policy ID. Confirm the active policy in `docs-mcp`, then fully restart Claude Desktop so the gateway reads the selected environment.

## Prove all three outcomes

Ask the host to call **the actual `docs_echo` tool on `kastra-docs-echo`**, with the following argument object. If a call is blocked, instruct it to stop rather than substitute another tool.

```json
{"message":"kastra-docs-allow"}
```

Expect tool output `echo completed: kastra-docs-allow` and an ALLOW event with source `mcp`, server `kastra-docs-echo`, and tool `docs_echo` in Activity.

```json
{"message":"kastra-docs-deny"}
```

Expect a gateway denial and a DENY event. There must be no successful `echo completed:` tool result for this call. A marker quoted by the assistant or in the error preview is not server execution.

```json
{"message":"kastra-docs-hold"}
```

Expect a pending approval before the echo response. Inspect and approve that checkpoint in the console; the waiting call should then return `echo completed: kastra-docs-hold`. Make a new call and deny its checkpoint to verify refusal. If the host stops waiting, inspect [approval status](https://docs.kastra.ai/approvals/overview) before retrying.

## Review and clean up

```sh
kastra evidence list --env docs-mcp --limit 20
kastra policy deactivate POLICY_ID
kastra-edge unwrap-claude-desktop --server kastra-docs-echo
```

Replace `POLICY_ID` with the example's recorded ID. Remove only the `kastra-docs-echo` entry from the host configuration, restore the previous Edge environment with `kastra-edge config set default_environment PREVIOUS_NAME`, and restart the host. You can now remove the two downloaded example files. Keep the inactive policy and decision records for review.

An unavailable evaluator can fail open on this integration. Unexpected execution without a matching event is a failed verification; inspect login, configuration, gateway logs and [failure behavior](https://docs.kastra.ai/reference/failure-behavior). Next, apply the same verification method to a real server in [local MCP setup](https://docs.kastra.ai/mcp/local-gateway).
