Porta v1.11.0
Skip to content

SDK AI Agent Guide ​

The @portaidentity/sdk/agent entrypoint enables AI agents (LLMs with function-calling) to manage Porta infrastructure through structured tool definitions. This is designed for MCP servers, OpenAI function-calling, LangChain tools, and similar agent frameworks.

Overview ​

The agent layer provides:

  1. Tool Definitions — Structured descriptions of all SDK operations, compatible with LLM function-calling schemas
  2. Tool Executor — A dispatcher that maps tool names to SDK method calls with parameter validation
┌──────────────┐     ┌──────────────┐     ┌──────────────┐
│  AI Agent    │────▶│  SDK Agent   │────▶│  SDK Client   │
│  (LLM)       │     │  Layer       │     │  (transport)   │
└──────────────┘     └──────────────┘     └──────────────┘
  function call      executeTool()       domain.method()

Quick Start ​

typescript
import { createPortaClient } from '@portaidentity/sdk';
import { createNodeTransport, createClientCredentialsAuth } from '@portaidentity/sdk/node';
import { getToolDefinitions, executeTool } from '@portaidentity/sdk/agent';

// 1. Create an authenticated client
const porta = createPortaClient({
  transport: createNodeTransport({
    baseUrl: 'https://porta.local:3443/api/admin',
    auth: createClientCredentialsAuth({
      tokenEndpoint: 'https://porta.local:3443/super-admin/token',
      clientId: process.env.PORTA_CLIENT_ID!,
      clientSecret: process.env.PORTA_CLIENT_SECRET!,
    }),
  }),
});

// 2. Get tool definitions for the AI model
const tools = getToolDefinitions();
// → 75 tool definitions with name, description, parameters, returns

// 3. Execute a tool from AI agent output
const result = await executeTool(porta, 'organizations.list', { pageSize: 10 });

Tool Definitions ​

Each tool definition includes:

FieldTypeDescription
namestringUnique tool name (e.g., organizations.create)
descriptionstringHuman-readable description for the LLM
parametersToolParameter[]Input parameters with types and descriptions
returnsstringDescription of the return value
sideEffectsbooleanWhether the tool modifies state
prerequisitesstring[]What must exist before calling this tool
relatedToolsstring[]Tools commonly used together

Example Tool Definition ​

typescript
{
  name: 'organizations.create',
  description: 'Create a new organization (tenant) in Porta',
  parameters: [
    { name: 'name', type: 'string', required: true, description: 'Organization display name' },
    { name: 'slug', type: 'string', required: false, description: 'URL-safe identifier (auto-generated if omitted)' },
    { name: 'defaultLocale', type: 'string', required: false, description: 'Default locale (e.g., "en")' },
  ],
  returns: 'Organization object with id, name, slug, status, timestamps',
  sideEffects: true,
  prerequisites: ['Authenticated as porta-admin'],
  relatedTools: ['applications.create', 'organizations.list'],
}

Listing All Tools ​

typescript
const tools = getToolDefinitions();
console.log(`Available tools: ${tools.length}`);

// Group by domain
const domains = new Set(tools.map((t) => t.name.split('.')[0]));
console.log('Domains:', [...domains]);
// → organizations, applications, clients, users, roles, permissions, ...

Executing Tools ​

The executeTool() function dispatches a tool call to the correct SDK domain method:

typescript
import { executeTool } from '@portaidentity/sdk/agent';

// The AI agent says: "call organizations.create with { name: 'Acme Corp' }"
const result = await executeTool(porta, 'organizations.create', {
  name: 'Acme Corp',
  slug: 'acme',
});

// result is the Organization object returned by porta.organizations.create()

Error Handling ​

typescript
const result = await executeTool(porta, toolName, toolArgs);
if (!result.success) {
  // The agent layer deliberately returns a minimal error and does not expose
  // transport, server, or validation details to the model.
  return { success: false, error: result.error };
}
return { success: true, data: result.data };

MCP Server Integration ​

To build an MCP server that exposes Porta tools:

typescript
import { McpServer } from '@anthropic-ai/mcp-sdk';
import { createPortaClient } from '@portaidentity/sdk';
import { createNodeTransport, createClientCredentialsAuth } from '@portaidentity/sdk/node';
import { getToolDefinitions, executeTool } from '@portaidentity/sdk/agent';

const porta = createPortaClient({
  transport: createNodeTransport({
    baseUrl: process.env.PORTA_API_URL!,
    auth: createClientCredentialsAuth({
      tokenEndpoint: process.env.PORTA_TOKEN_ENDPOINT!,
      clientId: process.env.PORTA_CLIENT_ID!,
      clientSecret: process.env.PORTA_CLIENT_SECRET!,
    }),
  }),
});

const server = new McpServer({ name: 'porta-admin', version: '1.0.0' });

// Register all Porta tools
for (const tool of getToolDefinitions()) {
  server.tool(
    tool.name,
    tool.description,
    Object.fromEntries(
      tool.parameters.map((p) => [p.name, { type: p.type, description: p.description }]),
    ),
    async (args) => {
      const result = await executeTool(porta, tool.name, args);
      return { content: [{ type: 'text', text: JSON.stringify(result, null, 2) }] };
    },
  );
}

await server.start();

OpenAI Function-Calling Integration ​

typescript
import { getToolDefinitions, executeTool } from '@portaidentity/sdk/agent';

// Convert to OpenAI function-calling format
const openAiTools = getToolDefinitions().map((tool) => ({
  type: 'function' as const,
  function: {
    name: tool.name,
    description: tool.description,
    parameters: {
      type: 'object',
      properties: Object.fromEntries(
        tool.parameters.map((p) => [
          p.name,
          {
            type: p.type,
            description: p.description,
          },
        ]),
      ),
      required: tool.parameters.filter((p) => p.required).map((p) => p.name),
    },
  },
}));

// Use with OpenAI API
const response = await openai.chat.completions.create({
  model: 'gpt-4',
  messages: [{ role: 'user', content: 'List all organizations' }],
  tools: openAiTools,
});

// Execute tool calls from the response
for (const toolCall of response.choices[0].message.tool_calls ?? []) {
  const args = JSON.parse(toolCall.function.arguments);
  const result = await executeTool(porta, toolCall.function.name, args);
  console.log(`${toolCall.function.name}:`, result);
}

Available Tool Domains ​

DomainToolsDescription
organizations7Org CRUD, status lifecycle, delete
applications6App CRUD, module deletion
clients7Client CRUD, secrets
users12User CRUD, invite, password, status
roles5Application roles and assigned-permission reads
permissions4Application permission CRUD
userRoles4User-role assignments and effective permissions
customClaims6Claim definitions and user claim values
config3System configuration
keys3Signing key management
audit1Audit log
stats2Dashboard statistics
sessions3Session management
bulk2Bulk status operations
twoFactor72FA administration and policy
exports1Selective portability manifest export
imports2Portability preview and atomic import

Portability tools are exports.manifest, imports.preview, and imports.apply. An agent must preview the exact manifest and obtain operator approval before apply. A successful apply can return new confidential-client secrets once; do not include those values in model messages, logs, or retained tool history.

RBAC Tool Examples ​

Role and permission tools always take an appId, which keeps each RBAC definition inside its application boundary. User-role tools additionally take the organization and selected user IDs.

typescript
await executeTool(porta, 'permissions.create', {
  appId: 'application-id',
  input: { name: 'Edit deals', slug: 'sales:deal:write' },
});

await executeTool(porta, 'userRoles.assign', {
  orgId: 'organization-id',
  userId: 'user-id',
  roleIds: ['role-id'],
});

roles.delete, permissions.delete, and userRoles.remove return a reauthenticationRequired flag. If it is true, discard the current admin authentication and authenticate again before sending another command. These agent tools perform the requested operation directly, so the calling agent must obtain user confirmation before destructive calls.

Security Considerations ​

  • The agent operates with the same permissions as the SDK client's authentication. Use a dedicated service account with minimal required permissions.
  • Side-effect awareness: Tools with sideEffects: true modify state. AI agents should confirm destructive actions such as organizations.delete with the user.
  • Rate limiting: The Porta API enforces rate limits. Agent loops that make many rapid requests may be throttled.
  • No credential exposure: Never pass credentials through tool parameters. Authentication is handled by the transport layer.

See Also ​

Released under the MIT License.