kavachOS

Agent discovery

Advertising and searching agent capabilities with A2A-compatible capability cards.

What capability cards are

A capability card is a JSON document an agent publishes to describe itself: what it can do, which protocols it speaks, and how callers must authenticate. Other agents or orchestrators query these cards to find the right agent for a given task.

KavachOS models this after the Google A2A Agent Card specification.

Agent cards follow the Google A2A Agent Card pattern. If you are building an orchestrator that already understands A2A discovery, the same query shape works here.

Data model

Prop

Type

AgentCapability

Prop

Type

Registering a card

Call kavach.discovery.registerCard with an agent ID and the card payload. The card is persisted in the database and immediately available for search.

const card = await kavach.discovery.registerCard('agt_abc123', {
  name: 'Code Reviewer',
  description: 'Reviews pull requests and suggests improvements.',
  version: '1.0.0',
  protocols: ['mcp', 'http'],
  capabilities: [
    {
      name: 'review_pr',
      description: 'Review a GitHub pull request and return inline comments.',
      inputSchema: {
        type: 'object',
        properties: {
          repo: { type: 'string' },
          prNumber: { type: 'number' },
        },
        required: ['repo', 'prNumber'],
      },
    },
    {
      name: 'summarize_diff',
      description: 'Summarize a unified diff into plain English.',
    },
  ],
  authRequirements: {
    type: 'bearer',
    scopes: ['mcp:read', 'mcp:execute'],
  },
  endpoint: 'https://agents.yourapp.com/code-reviewer',
});

console.log(card.id); // UUID

Searching cards

Use searchCards to find agents by protocol, capability name, or display name. All filters are optional and can be combined.

// Find all agents that support the MCP protocol
const mcpAgents = await kavach.discovery.searchCards({
  protocols: ['mcp'],
});

// Find agents with a specific capability
const reviewers = await kavach.discovery.searchCards({
  capabilities: ['review_pr'],
});

// Combine filters: MCP agents that can summarize diffs
const candidates = await kavach.discovery.searchCards({
  protocols: ['mcp'],
  capabilities: ['summarize_diff'],
});

// Full-text name search
const namedAgents = await kavach.discovery.searchCards({
  name: 'reviewer',
});

Protocol and capability filters are applied in the application layer after the database query, so JSON column semantics are consistent across SQLite, Postgres, and MySQL.

Fetching a single card

const card = await kavach.discovery.getCard('agt_abc123');

if (!card) {
  console.log('No card registered for this agent');
}

Updating a card

Pass any subset of the card fields. Only the fields you provide are updated; the rest stay the same.

await kavach.discovery.updateCard('agt_abc123', {
  version: '1.1.0',
  capabilities: [
    { name: 'review_pr', description: 'Review PRs with inline comments.' },
    { name: 'summarize_diff', description: 'Summarize diffs.' },
    { name: 'suggest_tests', description: 'Propose test cases for changed code.' },
  ],
});

Updating a card does not affect the agent's identity or permissions. It only changes what the discovery index advertises.

Removing a card

await kavach.discovery.removeCard('agt_abc123');

The agent itself is not revoked. Only the discovery entry is deleted.

Orchestrator pattern

A common use: an orchestrator receives a task, queries the discovery index for agents that can handle it, then delegates work via KavachOS authorization.

async function handleTask(task: { type: string; payload: unknown }) {
  // Find an agent with the right capability
  const candidates = await kavach.discovery.searchCards({
    capabilities: [task.type],
    protocols: ['mcp'],
  });

  if (candidates.length === 0) {
    throw new Error(`No agent registered for capability: ${task.type}`);
  }

  // Pick the first match (add your own ranking logic here)
  const card = candidates[0]!;

  // Authorize before invoking
  const authResult = await kavach.authorize(card.agentId, {
    action: 'execute',
    resource: `mcp:${task.type}`,
  });

  if (!authResult.allowed) {
    throw new Error(`Authorization denied: ${authResult.reason}`);
  }

  // Route request to card.endpoint
}

Next steps

On this page