---
title: Call MCP tools from your code
description: A step-by-step guide to calling an MCP server's tools through Veefore from a TypeScript or Python agent with the SDK.
---

This guide is for an agent you write yourself. Your code calls MCP tools
through the Veefore SDK instead of straight at the server, and Veefore checks
each call, calls the server with its own credential, and returns the server's
answer unchanged.

If your code already calls the server with the official MCP SDK, the CLI can
make this change for you: see [Reroute MCP calls with the CLI](/build/mcp-cli).
If you do not write code at all, use an
[MCP client](/build/mcp-client) instead.

**You will need:** Node.js 20.10 or newer (and Python 3.9+ for a Python agent),
an agent project, and a Veefore account. The example uses
[DeepWiki](https://mcp.deepwiki.com), which needs no token.

## Step by step

:::steps

:::step Set up the project with the CLI

In your agent project:

```bash
npm install -g veefore
cd your-agent-project
veefore
```

The CLI opens the console to sign you in, creates an **agent** for this project
in the **Development** environment, and writes two files:

- `veefore.config.json` — settings, no secrets; commit it.
- `.env.local` — the agent's private key and the gateway address; gitignored.
  The SDK reads it.

It also adds a starter policy as a draft. Answer `y` when it asks. If it offers
to change your code and you have no tools to wrap yet, you can skip that.
:::

:::step Connect the MCP server

1. Sign in at [console.veefore.com](https://console.veefore.com) and set the
   **Environment** switcher at the top to **Development** — the environment the
   CLI created your agent in.
2. Open **MCP** → **Connect server**.
3. Paste `https://mcp.deepwiki.com/mcp`, tick **I know who runs this server and
   trust it**, and click **Connect**.
4. Under **Agent**, tick the agent the CLI created (named after your project).
5. Keep the tools you want ticked and click **Authorize N tools**.

The server's **slug** — `deepwiki` here — is how your code names it. It is on
the server's page and in its address.
:::

:::step Install the SDK

:::tabs

:::tab TypeScript
```bash
npm install @veefore/sdk@1.8.0
```

`mcpServer()` needs 1.8.0 or later.
:::

:::tab Python
```bash
pip install veefore-py==1.7.0
```
:::

:::
:::

:::step Call a tool

:::tabs

:::tab TypeScript
```ts
import { mcpServer } from '@veefore/sdk';

const result = await mcpServer('deepwiki').callTool({
  name: 'read_wiki_structure',
  arguments: { repoName: 'modelcontextprotocol/typescript-sdk' },
});

console.log(result.content); // the server's own tools/call result
```

`mcpServer()` builds its client from `.env.local`. It has the same `callTool`
as the official MCP SDK's client, so if you already use one, change only the
receiver:

```ts
// Before
const result = await client.callTool({ name: 'read_wiki_structure', arguments });
// After
const result = await mcpServer('deepwiki').callTool({ name: 'read_wiki_structure', arguments });
```
:::

:::tab Python
```python
from veefore import guard_client

decision = guard_client().mcp_call(
    server="deepwiki",
    tool="read_wiki_structure",
    arguments={"repoName": "modelcontextprotocol/typescript-sdk"},
)
print(decision.result)  # the server's own tools/call result
```

`guard_client()` builds its client from `.env.local`, found from the current
directory upwards. Variables already set in the environment win, which is how
you configure it in production.
:::

:::
:::

:::step Run it, and check it worked

Run your agent as you normally do. To watch decisions as they happen, run
`veefore dev` in another terminal in the project.

Then open **Actions** in the console. The call is listed with your agent, the
tool `mcp_deepwiki_read_wiki_structure`, the decision and the time.
:::

:::step Decide what happens when a person must approve

If a rule requires approval, the SDK waits for the decision by default. A chat
agent usually should not block its turn, so it can defer instead:

```ts
import { isAwaitingApproval, mcpServer } from '@veefore/sdk';

const outcome = await mcpServer('deepwiki', { onApproval: 'defer' }).callTool({
  name: 'ask_wiki_question',
  arguments: { repoName: 'facebook/react', question: 'How does reconciliation work?' },
});
if (isAwaitingApproval(outcome)) return outcome.say; // tell the user, carry on
```

On a later turn, `resumeApprovals()` finds the decision and, if it was approved,
performs the call once. The modes are `'wait'` (default), `'defer'` and
`'throw'`; `VEEFORE_APPROVAL_MODE` sets the default for the project. See
[Handle approvals](/build/handle-approvals).
:::

:::step Turn on protection

New environments start in **Observe**: calls run and are recorded, and nothing
is blocked. When you have watched it for a while:

```bash
veefore policies test
veefore deploy --mode ENFORCE --reason "MCP tools reviewed"
```

`policies test` shows which recent calls would start being refused before
anything changes. See [What your rules do](/build/mcp-client#what-your-rules-do)
for how MCP calls are decided.
:::

:::

## When a call is refused

Under **Enforce**, a refused call throws `VeeforeBlockedError` in TypeScript
(and raises in Python) with the reason, and the server is never contacted:

```ts
import { VeeforeBlockedError, mcpServer } from '@veefore/sdk';

try {
  await mcpServer('deepwiki').callTool({ name: 'ask_wiki_question', arguments });
} catch (error) {
  if (error instanceof VeeforeBlockedError) console.warn(error.message);
  else throw error;
}
```

[MCP troubleshooting](/build/mcp-troubleshooting) lists every refusal and its
fix.

## Without the SDK

The SDK calls one gateway endpoint, `POST /gateway/v1/mcp/call`, with a session
token from the agent's signed identity. Any language can do the same; see
[Sign your own assertion](/build/sign-your-own-assertion) and the
[JavaScript SDK](/build/javascript-sdk) reference for `mcpCall()`.

## Related

:::cards

:::card MCP overview | /build/mcp
How Veefore handles MCP servers.
:::

:::card Reroute MCP calls with the CLI | /build/mcp-cli
Let `veefore integrate` make the change.
:::

:::card Handle approvals | /build/handle-approvals
Wait, defer or throw.
:::

:::
