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

# Add Praxa tools to an agent

> Register the published Praxa MCP contracts in Vercel AI SDK, OpenAI, or another MCP-compatible host and verify least-privilege execution.

Praxa publishes two complementary packages:

* `@praxa/mcp-contracts` contains 12 protocol-only tool definitions.
* `@praxa/sdk` contains `createPraxaAgentTools()`, which binds the same
  operations to a `PraxaClient`.

Both packages are version `0.3.0`. They contain no provider credential or
server-side action authority.

## Prerequisites

Before you begin, prepare:

* the exact published Praxa package versions used by the tutorial;
* a trusted agent host with explicit tool, approval, timeout, and output policies;
* deployment-specific OAuth or backend-owned provider clients where the selected lane requires them;
* synthetic tenant, subject, prompt, and tool fixtures for positive and adversarial tests;
* an acceptance assertion that proves the host registers 12 exact tools and passes safe-read, wrong-scope, approval, and replay canaries.

## 1. Install and create the client

```bash theme={null}
npm install @praxa/sdk@0.3.0 @praxa/mcp-contracts@0.3.0
```

```ts theme={null}
import { createPraxaAgentTools, PraxaClient } from "@praxa/sdk";

const client = new PraxaClient({
  baseUrl: process.env.PRAXA_BASE_URL!,
  accessToken: () => process.env.PRAXA_ACCESS_TOKEN!,
});

const definitions = createPraxaAgentTools(client);
```

Keep the client and token on a trusted server.

## 2. Connect an agent framework

<Tabs>
  <Tab title="Vercel AI SDK">
    The AI SDK accepts raw JSON Schema through `jsonSchema()`.

    ```ts theme={null}
    import { jsonSchema, tool, ToolLoopAgent } from "ai";

    const tools = Object.fromEntries(
      definitions.map((definition) => [
        definition.name,
        tool({
          description: definition.description,
          inputSchema: jsonSchema(definition.inputSchema),
          execute: definition.execute,
          needsApproval: !definition.readOnly,
        }),
      ]),
    );

    const agent = new ToolLoopAgent({ model, tools });
    const result = await agent.generate({ prompt: "Prepare the weekly review" });
    console.log(result.text);
    ```

    Framework approval is defense in depth. Praxa still performs server-side
    scope, tenant, policy, purpose, and revocation checks.
  </Tab>

  <Tab title="OpenAI remote MCP">
    Use the deployment's `/mcp` endpoint when your OpenAI runtime supports
    remote MCP. Keep approval enabled for remote calls.

    ```ts theme={null}
    const response = await openai.responses.create({
      model: "your-reviewed-model",
      input: "Prepare the weekly review",
      tools: [{
        type: "mcp",
        server_label: "praxa",
        server_url: `${process.env.PRAXA_BASE_URL}/mcp`,
        authorization: process.env.PRAXA_ACCESS_TOKEN,
        require_approval: "always",
      }],
    });
    ```
  </Tab>

  <Tab title="Framework-neutral host">
    MCP libraries differ in how they accept raw JSON Schema. Adapt the schema,
    but preserve the exported name, description, and annotations.

    ```ts theme={null}
    import { PRAXA_MCP_TOOLS } from "@praxa/mcp-contracts";

    for (const definition of PRAXA_MCP_TOOLS) {
      host.registerJsonSchemaTool({
        name: definition.name,
        description: definition.description,
        inputSchema: adaptJsonSchema(definition.inputSchema),
        annotations: definition.annotations,
      }, (args) => dispatchToPraxaClient(definition.operationId, args));
    }
    ```
  </Tab>
</Tabs>

## 3. Preserve the wire identifiers

The packages use Praxa-branded exports, but compatibility wire values remain
Aura-named:

```ts theme={null}
import {
  MCP_PROTOCOL_VERSION,
  MCP_LEGACY_PROTOCOL_VERSION,
  MCP_SERVER_NAME,
  MCP_SERVER_VERSION,
  PRAXA_MCP_TOOLS,
} from "@praxa/mcp-contracts";

console.log(MCP_PROTOCOL_VERSION);        // 2025-11-25
console.log(MCP_LEGACY_PROTOCOL_VERSION); // 2025-03-26
console.log(MCP_SERVER_NAME);             // aura-agent-os
console.log(MCP_SERVER_VERSION);          // 0.3.0
console.log(PRAXA_MCP_TOOLS[0].name);      // aura_submit_intent
```

Do not rename `aura_*` tools on the wire. A display label in your own UI may use
Praxa branding, but discovery and invocation must use the exported value.

## 4. Start with read-only tools

```ts theme={null}
const readOnlyDefinitions = definitions.filter(
  (definition) => definition.readOnly,
);
```

Give the OAuth token only the corresponding read scopes. Add mutation tools
after your application has an explicit approval and stable idempotency-key
policy.

## 5. Verify the integration

```ts theme={null}
import { strict as assert } from "node:assert";
import {
  MCP_PROTOCOL_VERSION,
  MCP_SERVER_NAME,
  MCP_SERVER_VERSION,
  PRAXA_MCP_TOOLS,
} from "@praxa/mcp-contracts";

assert.equal(PRAXA_MCP_TOOLS.length, 12);
assert.equal(MCP_PROTOCOL_VERSION, "2025-11-25");
assert.equal(MCP_SERVER_NAME, "aura-agent-os");
assert.equal(MCP_SERVER_VERSION, "0.3.0");
assert.ok(PRAXA_MCP_TOOLS.every((tool) => tool.name.startsWith("aura_")));
assert.ok(PRAXA_MCP_TOOLS.every((tool) => tool.annotations));
```

Then run a disposable deployment canary:

1. List tools and require all expected exported wire names.
2. Invoke a safe read with the matching scope.
3. Invoke that read without its scope and require `403`.
4. Invoke a keyed mutation twice with the same body and require one logical mutation.
5. Change the body while reusing the key and require a conflict.
6. Revoke the token and require subsequent tool calls to fail closed.
7. Confirm the framework never receives or logs a provider credential.

<Note>
  Import and schema tests prove the package. The disposable canary proves your
  framework adapter, OAuth issuance, Gateway deployment, and server-side policy
  boundary together.
</Note>

## Troubleshooting

| Symptom                              | Resolution                                                                                    |
| ------------------------------------ | --------------------------------------------------------------------------------------------- |
| Package imports but nothing executes | Separate package contracts from the deployment or provider executor they describe.            |
| Agent selects the wrong tool         | Shrink the allowlist and improve the specific tool description and task policy.               |
| Mutation repeats after timeout       | Persist the exact input and idempotency key, then reconcile before a new call.                |
| Tool output changes agent intent     | Treat tool content as untrusted data and preserve the original purpose and approval boundary. |

## Best practices

* Enable the smallest tool or source set needed for the workflow.
* Require approval for mutations and independently for destructive actions.
* Derive tenant, subject, purpose, and credential from trusted host context.
* Bound tool inputs, output bytes, concurrent calls, retries, and total turn time.
* Verify a run, event, trace, receipt, or source status independently of model prose.

## Optimize for production

* Reduce tool definitions and provider sources to the relevant set before each turn.
* Use deterministic filtering and pagination before placing results in model context.
* Cache only versioned, non-sensitive contracts and read-only metadata.
* Measure tool-selection accuracy, approval rate, p50/p95 call latency, context bytes, retries, and verified completion.

Optimize only after the correctness and isolation matrix passes. Lower latency or cost is not an improvement if verified outcomes, authority checks, or recovery rates regress.

## Cleanup and next steps

1. Revoke disposable delegated grants and remove test host configuration.
2. Delete provider fixtures through the provider's own lifecycle when applicable.
3. Disable mutation tools until their negative and approval tests pass again after upgrades.
4. Retain only redacted tool, run, trace, and receipt identifiers needed for evaluation.

After cleanup, run the [shared integration test matrix](/tutorials/test-your-integration) and record any environment-specific check that remains pending.

## Frequently asked questions

### What proves this tutorial works?

The minimum observable result is that the host registers 12 exact tools and passes safe-read, wrong-scope, approval, and replay canaries. A compile, package import, mocked response, or initial admission alone does not prove the complete workflow.

### Can a browser, mobile app, or model prompt hold the credential?

Only a trusted server or agent host may hold delegated Praxa or provider credentials. Never place them in model input or client bundles.

### How should an ambiguous mutation be retried?

Persist the exact logical input and idempotency key before the first attempt. Reconcile through authoritative readback or replay the exact request with that same key before creating new work.

### What should we monitor after release?

Monitor tool-selection accuracy, approval decisions, call latency, context size, retries, denials, and verified outcomes. Alert on authorization bypass, cross-tenant disclosure, repeated conflicts, or cleanup failure.
