Skip to main content
Workflows Library MCP Directory Realtime AI News Sponsor Tier Subscribe
Front Page / AI Tools / Deep Dive

ARD MCP Server: Discover & Route Agent Tools Across the Web

Google's Agentic Resource Discovery (ARD) protocol, built under the Linux Foundation AAIF, lets an agent ask what is available before anything runs. This guide builds a stateless ARD-style MCP discovery server that indexes plugins, MCP servers, and skills and answers query-by-task searches with ranked, cacheable results.

Deepak Bagada

Deepak Bagada

CEO, SaaSNext

Aug 11, 2026 Published
|
Aug 11, 2026 Updated
|
9 Minutes Reading Time
Core Takeaways for Founders & Builders
  • ARD (Agentic Resource Discovery) is an AAIF/Linux Foundation protocol, led by Google, that answers what is available for a task before any tool is invoked.
  • Plugins are a first-class ARD resource type; the proposed application/agent-plugins+json MIME type lets an AI Catalog entry point at a plugin.json.
  • A stateless MCP server can index plugins, MCP servers, and skills and rank query-by-task matches with SEP-2549 cacheScope/ttlMs hints.
  • Deploy per MCP 2026-07-28 request/response semantics with OAuth 2.0 (RFC 8707 resource indicators) for remote catalogs.

ARD MCP Server: Find & Route Agent Tools Across the Web

What is Agentic Resource Discovery (ARD)?

Every agent that runs more than two or three MCP servers hits the same wall: the client can only call tools it has been explicitly wired to know about. Everything else in the organization — the marketing stack, the data platform, the internal APIs — stays invisible until somebody hand-edits a config file. In August 2026, the Linux Foundation's Agentic AI Foundation (AAIF), with Google leading the design work, published a protocol that removes that wall: Agentic Resource Discovery (ARD).

ARD is an open discovery protocol built around one operation: the client asks "What is available for this task?" and receives a ranked set of matching resources. The word resource is deliberately broad. In ARD's model, an agent, an MCP server, a Skill, and — new under the Agent Plugins 1.0.0 spec — a Plugin are all first-class agentic resource types. That single abstraction is what lets one discovery layer span everything from a single-tool MCP server to a full plugin bundle to a complete agent.

Crucially, ARD sits entirely before invocation. Discovery never runs a tool, never spawns a server, and never executes a skill. It returns pointers, metadata, and confidence scores; the client decides what to invoke next. Discovery is cheap, cacheable, and safe to run on every single user turn, while invocation stays expensive, authorized, and scoped.

The companion entry format ARD indexes is the AI Catalog — a machine-readable file published at a well-known URL that enumerates the resources an entity exposes. A proposed change in the ARD design registers the MIME type application/agent-plugins+json, so a catalog entry can point at a plugin.json exactly the way it points at an agent card or an mcp.json. That detail is the bridge between the discovery world and the Agent Plugins packaging world: a catalog does not need to understand how a plugin is built internally, only where its manifest lives.

Why find-and-route is the missing layer

Before ARD, tool utilization in most agent deployments is poor. Teams install a server, forget it exists, and the agent never surfaces it at the moment it matters. Find-and-route changes the economics:

  1. Query by task, not browse by name. Instead of remembering that pdf-summarizer exists, the user describes the outcome: "summarize this PDF." The catalog returns ranked candidates across plugins, MCP servers, skills, and agents.
  2. Routing without execution. Because ARD sits before invocation, a client can query several catalogs, assemble a shortlist, and then invoke the winner through MCP's normal tools/call flow.
  3. Freshness at the edge. The SEP-2549 caching extension — cacheScope plus ttlMs — lets a stateless server attach cache hints to every discovery response, so per-turn lookups stay fast without serving stale resources.

The ARD MCP server in this guide turns those properties into a deployable tool. It indexes plugins, MCP servers, and skills from a catalog, answers query-by-task searches, and returns ranked matches annotated with SEP-2549 cache hints — all built stateless per the MCP 2026-07-28 spec (request/response, no session).

Indexing, ranking, and cache hints in practice

The server keeps two in-memory structures: an id-keyed map of every registered resource and a task-keyword index that maps verbs and nouns back to the entries that serve them. Scoring is intentionally transparent: exact task-keyword hits weigh most, followed by name matches and description overlap. Every stored entry also carries a cacheScope (request, session, or global) and a ttlMs bound, which the server echoes into each match so clients can cache discovery responses safely.

A response to catalog_search_by_task looks like this:

{
  "task": "summarize this PDF",
  "matches": [
    {
      "id": "plug-1",
      "type": "plugin",
      "name": "doc-suite",
      "source": "https://registry.example.com/doc-suite/plugin.json",
      "mime": "application/agent-plugins+json",
      "score": 3.5,
      "cacheScope": "global",
      "ttlMs": 300000
    },
    {
      "id": "srv-7",
      "type": "mcp_server",
      "name": "pdf-tools",
      "source": "https://mcp.example.com/pdf/mcp.json",
      "mime": null,
      "score": 2.5,
      "cacheScope": "session",
      "ttlMs": 60000
    }
  ]
}

Because ARD resolves nothing at discovery time, these results are safe to cache and cheap to produce — which is exactly why the protocol is designed to run on every turn, not just on demand.

Tool reference

Tool What it does Returns
catalog_search_by_task Query-by-task discovery across the index Ranked matches + cache hints
catalog_register_resource Ingest a resource (URL or inline JSON) into the catalog Entry id
catalog_resolve_plugin Resolve a plugin entry to its plugin.json location application/agent-plugins+json target
catalog_get_entry Fetch one entry by id Full metadata
catalog_list_types Enumerate supported resource types agent, mcp_server, skill, plugin
catalog_unregister_resource Remove an entry Status

catalog_search_by_task inputSchema

{
  "name": "catalog_search_by_task",
  "description": "Search the ARD catalog for resources that can perform a task.",
  "inputSchema": {
    "type": "object",
    "properties": {
      "task": { "type": "string", "description": "Free-form task, e.g. 'summarize this PDF'" },
      "types": {
        "type": "array",
        "items": { "type": "string", "enum": ["plugin", "mcp_server", "skill", "agent"] },
        "description": "Optional resource-type filter"
      },
      "limit": { "type": "integer", "minimum": 1, "maximum": 25, "default": 10 }
    },
    "required": ["task"]
  }
}

catalog_register_resource inputSchema

{
  "name": "catalog_register_resource",
  "inputSchema": {
    "type": "object",
    "properties": {
      "source": { "type": "string", "description": "AI Catalog URL, plugin.json URL, or inline JSON" },
      "type": { "type": "string", "enum": ["plugin", "mcp_server", "skill", "agent"] },
      "name": { "type": "string", "description": "Human-readable resource name" },
      "tasks": { "type": "array", "items": { "type": "string" }, "description": "Task keywords used for ranking" }
    },
    "required": ["source", "type", "name"]
  }
}

catalog_resolve_plugin inputSchema

{
  "name": "catalog_resolve_plugin",
  "inputSchema": {
    "type": "object",
    "properties": {
      "entry_id": { "type": "string", "description": "Catalog entry id of a plugin resource" }
    },
    "required": ["entry_id"]
  }
}

The full TypeScript server

import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";

type ResourceType = "plugin" | "mcp_server" | "skill" | "agent";

interface ResourceEntry {
  id: string;
  type: ResourceType;
  name: string;
  description: string;
  tasks: string[];
  source: string;
  mime?: string;                          // e.g. application/agent-plugins+json
  cacheScope: "global" | "session" | "request";  // SEP-2549
  ttlMs: number;                          // SEP-2549
}

const catalog = new Map<string, ResourceEntry>();

function score(task: string, entry: ResourceEntry): number {
  const t = task.toLowerCase();
  let s = entry.tasks.some((k) => t.includes(k.toLowerCase())) ? 2 : 0;
  s += t.includes(entry.name.toLowerCase()) ? 1.5 : 0;
  s += entry.description.toLowerCase().includes(t) ? 1 : 0;
  return s;
}

const server = new McpServer({ name: "ard-discovery", version: "0.1.0" });

server.registerTool(
  "catalog_search_by_task",
  {
    description: "Query-by-task discovery over the ARD catalog.",
    inputSchema: {
      type: "object",
      properties: {
        task: { type: "string" },
        types: { type: "array", items: { type: "string", enum: ["plugin", "mcp_server", "skill", "agent"] } },
        limit: { type: "integer", minimum: 1, maximum: 25, default: 10 }
      },
      required: ["task"]
    }
  },
  async ({ task, types, limit = 10 }) => {
    const matches = [...catalog.values()]
      .filter((e) => !types || types.includes(e.type))
      .map((e) => ({
        id: e.id, type: e.type, name: e.name, source: e.source,
        mime: e.mime ?? null, score: score(task, e),
        cacheScope: e.cacheScope, ttlMs: e.ttlMs
      }))
      .sort((a, b) => b.score - a.score)
      .slice(0, limit);

    return {
      content: [{ type: "text", text: JSON.stringify({ task, matches }, null, 2) }]
    };
  }
);

// catalog_register_resource, catalog_resolve_plugin, catalog_get_entry,
// catalog_list_types and catalog_unregister_resource follow the same
// registerTool pattern with the inputSchema reference above.

const transport = new StdioServerTransport();
await server.connect(transport);

mcpServers config for Claude Desktop and Cursor

The exact same block works in Claude Desktop's claude_desktop_config.json and in Cursor's .cursor/mcp.json:

{
  "mcpServers": {
    "ard-discovery": {
      "command": "npx",
      "args": ["-y", "@dailyaiworld/ard-discovery-server"],
      "env": {
        "ARD_CATALOG_URL": "https://catalog.dailyaiworld.com/ai-catalog.json",
        "ARD_CACHE_TTL_MS": "60000"
      }
    }
  }
}

Because the server is stateless, both clients can point at the same catalog and share the index; each request is authorized on its own, so no session state leaks between applications.

OAuth 2.0 and the security model

  • Discovery is read-only. catalog_search_by_task never executes remote code, so the worst a poisoned catalog can do is rank a bad resource — which invocation-time authorization still catches.
  • RFC 8707 resource indicators. When a catalog is remote and protected, the client requests a token with the catalog URL in the resource parameter, yielding audience-scoped access tokens instead of broad grants.
  • Minimal scopes. catalog:read for search and read operations; catalog:write for register and unregister. Deny by default.
  • No sessions, per MCP 2026-07-28. Requests are request/response only; every call carries its own credentials, and caching is bounded by ttlMs, never by session state.
  • Validate before you trust. Treat any plugin.json or mcp.json reached through a catalog as untrusted data. Checksum-pin critical entries and re-validate on every update.

Deployment notes

Run the server stateless so one instance — or many behind a load balancer — serves every client. Seed the index at boot from an AI Catalog URL and refresh it on a timer; for multi-region deployments, put the catalog behind a CDN and let SEP-2549 global cache hints do the heavy lifting. When you outgrow stdio, expose the same tools over Streamable HTTP and terminate TLS at the gateway.

Where ARD fits in your stack

Pair ARD discovery with the tools in the MCP directory, route its results through the patterns in our workflows, and watch the latest AI news for the final ARD spec as AAIF moves it toward release. The biggest wins come from wiring ARD into your agent bootstrap: resolve resources at plan time, cache them with SEP-2549 hints, and only then invoke.

FAQ

What exactly is Agentic Resource Discovery?

ARD is an open discovery protocol being built by Google through the Linux Foundation's Agentic AI Foundation. It lets a client ask "what is available for this task?" and receive matching resources — agents, MCP servers, skills, and plugins — ranked by fit. It operates entirely before invocation: nothing executes during discovery.

How is ARD different from MCP?

MCP is the invocation protocol: it defines how a client calls tools on a server. ARD is the discovery protocol: it tells the client what resources exist and which ones fit a task. They compose — ARD finds, MCP executes.

What is SEP-2549 cacheScope/ttlMs?

SEP-2549 is the MCP caching extension used in the 2026 MCP spec. cacheScope declares whether a response may be reused within a request, a session, or globally, and ttlMs bounds how long a cached response stays fresh. For a stateless discovery server, returning these hints per match lets clients cache catalog lookups aggressively without serving stale resources.

By Deepak Bagada, CEO at SaaSNext & Principal AI Architect.

Executive Briefing

Enjoyed this breakdown? Get our morning dispatch in your inbox.

Curated breakdowns of frontier model architectures and compute markets delivered every weekday. Zero fluff.

Frequently Asked Questions
ARD is an open discovery protocol being built by Google through the Linux Foundation's Agentic AI Foundation. It lets a client ask what is available for this task and receive matching resources - agents, MCP servers, skills, and plugins - ranked by fit. It operates entirely before invocation: nothing executes during discovery.
MCP is the invocation protocol: it defines how a client calls tools on a server. ARD is the discovery protocol: it tells the client what resources exist and which ones fit a task. They compose - ARD finds, MCP executes.
SEP-2549 is the MCP caching extension used in the 2026 MCP spec. cacheScope declares whether a response may be reused within a request, a session, or globally, and ttlMs bounds how long a cached response stays fresh. For a stateless discovery server, returning these hints per match lets clients cache catalog lookups aggressively without serving stale resources.
Deepak Bagada
Author Profile

Deepak Bagada

CEO, SaaSNext

Deepak Bagada is the CEO of SaaSNext and founder of Daily AI World. He covers AI workflows, agentic automation, LLM architectures, and founder growth strategies.

Related Intelligence Analysis

Briefing AI Tools

Vercel AI SDK Tool Calling React: 5 Steps (2026)

Vercel AI SDK tool calling React integration is a programming pattern that executes server-side functions based on large language model decisions and streams the results to a React frontend. By combining streamText with...

Deepak Bagada Deepak Bagada
12m read
Breaking AI Tools

Fact-Density vs. Word Count: The New SEO for 2026

Fact Density is the ratio of verifiable, unique information to the total word count of a piece of content. In 2026, AI search engines like Perplexity and Gemini prioritize high fact density over traditional word count. A...

Deepak Bagada Deepak Bagada
4m read
Audio Briefing
Accessibility Preferences
High Contrast Mode
Accessible Reading Font

Keyboard Shortcuts

Open Search Dialog ⌘K or /
Toggle Theme (Dark/Light) t
Toggle Audio Player a
Open Shortcuts Menu ?
Close Active Dialog Esc