API Documentation
The neutral graph where software is discovered, trusted, and invoked — for the agents that use it and the humans who build it. /api/v1/resolve is the agent-runtime entry point;/api/v1/search is the human-search surface. Every call feeds the same graph.
/<x> (User mode — marketing-polished, search-driven) and /agent/<x> (Agent mode — linearized markdown, no animations, code-first). The toggle is top-left of every page. Agents and LLMs that prefer markdown should hit the /agent/ mirror; humans get the polished surface by default.POST /api/v1/resolve
Agent has an intent — "send email", "query Postgres", "generate an image" — and gets back a verified, current, invocation-ready answer. One call. Trusted artifact + ready-to-run snippet + signed passport + alternatives + match confidence. This is the call every agent should make before it picks a tool at runtime.
curl -X POST https://unfragile.ai/api/v1/resolve \
-H "Content-Type: application/json" \
-d '{
"intent": "send email from agent",
"limit": 1
}'Response shape
{
"resolved": [{
"artifact": { "name": "...", "slug": "...", "type": "mcp", "url": "..." },
"capability": {
"id": "...",
"name": "...",
"intent": "send email from agent",
"description": "...",
"whyThisMatches": "...",
"vsAlternatives": "...",
"bestFor": ["..."],
"limitations": ["..."]
},
"invocation": {
"language": "mcp",
"snippet": "claude mcp add ... -- npx -y ...",
"requires": ["claude-code CLI installed"]
},
"trust": {
"verified": false,
"signature": "<Ed25519 base64>",
"signedAt": "2026-05-24T...Z",
"signedBy": "unfragile.ai",
"version": 1,
"unfragile": { /* full passport body */ }
},
"alternatives": [{ "slug": "...", "name": "...", "why_alternative": "..." }],
"matchConfidence": 0.87,
"lastVerified": "2026-05-22T...",
"feedbackUrl": "https://unfragile.ai/api/feedback",
"callbackToken": "<HMAC bound to resolveId + this artifact's slug>"
}],
"resolvedAt": "2026-05-24T...Z",
"resolveId": "resolve_1716..._a1b2c3",
"resolverVersion": "v6"
}Cached 1h. Cold-path target < 800ms p99. Cached path < 50ms p99. Verify the trust passport offline against the public key at /trust.
Closing the loop: report the outcome
Every resolved item carries a feedbackUrl and a callbackToken, and the response carries a top-level resolveId. The token is an HMAC binding the report to this resolution — the exact (resolveId, slug)pair — so an agent can't forge a success/fail signal for an arbitrary artifact. The loop is: resolve → invoke the tool → POST the real outcome to feedbackUrl, echoing the callbackToken and resolveIdyou were handed. Reported outcomes feed the match graph so the next agent's resolution is better grounded.
# After invoking the resolved tool, report what actually happened.
curl -X POST https://unfragile.ai/api/feedback \
-H "Content-Type: application/json" \
-d '{
"resolveId": "resolve_1716..._a1b2c3",
"slug": "<resolved artifact slug>",
"callbackToken": "<the callbackToken from that resolved item>",
"outcome": "success",
"feedback": "sent the email in one call"
}'outcome is "success" or "fail"; feedback is an optional free-text note. The endpoint returns { "ok": true, "matchGraph": true }.
POST /api/v1/verify
Call this before an agent invokes or installs a tool, MCP server, or package. Pass the install target and get back a single signed verdict —trusted·caution·unverified·flagged— computed from identity + typosquat checks, the MCP CVE/incident registry, data-access risk, and cross-vendor reputation. Conservative by design: nevertrusted on an unknown.
curl -X POST https://unfragile.ai/api/v1/verify \
-H "Content-Type: application/json" \
-d '{
"target": "mcp:@modelcontextprotocol/server-postgres",
"action": "read"
}'Response shape (signed)
{
"@type": "unfragile_verify_v1",
"target": { "canonical": "...", "name": "...", "package": "...", "type": "mcp" },
"verdict": "trusted" | "caution" | "unverified" | "flagged",
"identity": { "matched": true, "canonical": "...", "verifiedBuilder": false,
"typosquatRisk": null },
"safety": { "score": 0-100, "dataAccessRisk": "low|moderate|high",
"permissions": ["data.read"], "flags": ["known-cve:...","thin-reputation"] },
"reputation": { "timesInvoked": 12840, "successRate": 0.94, "firstSeenDays": 210,
"unfragileRank": 77 },
"summary": "Trusted — verified builder, 94% success over 12840 matches, low risk.",
"signature": "<Ed25519 base64>", "signedBy": "unfragile.ai", "auditId": "uuid",
"compliance": { "auditId": "uuid", "loggedAt": "...",
"evidenceUrl": "https://unfragile.ai/audit/<auditId>" },
"_links": { "verify_key": "https://unfragile.ai/api/v1/trust-passport-public-key" }
}Every call is signed (verify offline against the public key) and emits a tamper-evident audit record — defensible evidence of tool-trust due diligence (e.g. EU AI Act Annex III logging). Retrieve it at GET /api/v1/audit/{auditId} or the human page /audit/{auditId}.
Verify before you install (CLI guard)
The same check, wrapped around your install command. guardruns the command only if the target isn't flagged:
# install the CLI once
npm i -g @unfragile/mcp-server
# check a target
unfragile verify mcp:@modelcontextprotocol/server-postgres
# guard a real install — blocks on a flagged verdict
unfragile guard -- claude mcp add pg -- npx -y @scope/pg-mcp
# no install? run on demand:
npx -p @unfragile/mcp-server unfragile verify npm:postmark-mcpFor builders: register & sign — POST /api/v1/register
The supply side of verify. Declare your tool's identity + scope and get back a signed registration attestation and a hostableunfragile.yml. Honest by design: the signature attests the declaration; proving ownership (a 6-digit claim code at /submit) is what makes your verdict trusted — registration alone never inflates trust.
curl -X POST https://unfragile.ai/api/v1/register \
-H "Content-Type: application/json" \
-d '{
"target": "npm:@yourco/mcp",
"declaredPermissions": ["data.read"],
"declaredCapabilities": ["vector search"],
"contactEmail": "dev@yourco.com"
}'Only the contact domain goes into the signed object — never the full email. Returnsregistration (signed),unfragileYml, and anextStep claim link.
Why route through Unfragile
Agents have weak self-knowledge. Their confidence, cost estimates, and capability claims need an independent reference. Unfragile is the neutral graph where software is discovered, trusted, and invoked — a signed, verifiable source of truth about what each AI artifact can actually do, evidenced by observed outcomes and cryptographically attested by the trust passport.
- Neutrality. Every other registry has an artifact to push. LangChain prefers LangChain tools. AWS Agent Registry prefers Bedrock. OpenAI ranks GPT first. Unfragile is the only provider without a horse in the race — and the schema is open at/schema.json.
- Signed trust. Every
resolveresponse includes an Ed25519-signed trust passport. Compliance, procurement, and insurance workflows can verify offline using the published public key — no roundtrip to Unfragile required. - Capability-level evidence. Search results are tied to specific capabilities with intent, conditions, and observed match outcomes — not bare URLs. The graph learns from every invocation regardless of where it happens.
- Adoption pattern.Trust signals become industry standards when they are below the competitive layer and easier to adopt than to build. Google's SynthID followed this pattern for AI-generated content; signed capability resolution follows it for AI agents.
Native install in Claude Code / Cursor / Windsurf
Unfragile's MCP server wraps the resolve + trust-passport surface so any MCP-capable agent runtime can call it natively. One install, all tools available.
claude mcp add unfragile -- npx -y @unfragile/mcp-serverAuthentication
Authentication is optional. Unauthenticated requests are rate-limited to 60/min per IP. Authenticated requests get 300/min and are tracked for analytics.
Pass your API key via either header:
# Option 1: Authorization header
curl -H "Authorization: Bearer YOUR_API_KEY" \
"https://unfragile.ai/api/v1/search?q=mcp+server+for+slack"
# Option 2: X-API-Key header
curl -H "X-API-Key: YOUR_API_KEY" \
"https://unfragile.ai/api/v1/search?q=mcp+server+for+slack"GET /api/v1/search
Capability-based hybrid search. Returns matched artifacts with capabilities, UnfragileRank scores, and graph-backed social proof. Best fit when a human wants a ranked list and reasoning — agents should call resolve instead.
Parameters
| Param | Type | Required | Description |
|---|---|---|---|
| q | string | Yes | Search query (2-500 chars) |
| limit | integer | No | Max results, 1-20 (default: 5) |
| type | string | No | Filter by artifact type (agent, model, mcp, repo, etc.) |
| source | string | No | Your app name (for graph attribution) |
| fresh | boolean | No | fresh=true (alias sort=newest) biases toward recently-indexed, long-tail results — the frontier general LLMs likely miss |
Frontier queries & freshness signals
Pass fresh=true (or its alias sort=newest) to bias ranking toward recently-indexed, long-tail software — the frontier that general LLMs likely miss. Independent of that flag, every result's artifact object carries three freshness fields:
firstSeenDays— number of days since Unfragile first indexed this artifact.isFresh—truewhen first seen within the last 90 days.llmBlindSpot—truewhen fresh and low-adoption: a strong candidate for something outside an LLM's training data.
# Frontier query — surface the newest, long-tail MCP servers first.
curl "https://unfragile.ai/api/v1/search?q=mcp+server+for+postgres&type=mcp&fresh=true"Response
{
"query": "best code editor with AI",
"intent": {
"type": "tool_search",
"category": "ai-coding",
"refined": "AI-powered code editor with chat and autocomplete"
},
"matches": [
{
"artifact": {
"id": "cursor",
"name": "Cursor",
"type": "product",
"url": "https://cursor.com",
"slug": "cursor",
"description": "AI-first code editor built on VS Code",
"categories": ["ai-coding"],
"pricing": { "model": "freemium", "free": false },
"verified": true,
"unfragileRank": 82.5,
"firstSeenDays": 412,
"isFresh": false,
"llmBlindSpot": false,
"pageUrl": "https://unfragile.ai/cursor",
"passportUrl": "https://unfragile.ai/api/v1/passport/cursor"
},
"capabilities": [
{
"name": "Codebase-Aware Code Editing",
"description": "Edits code with full project context...",
"matchScore": 0.94,
"bestFor": ["large codebases", "multi-file refactoring"],
"limitations": ["requires VS Code familiarity"]
}
],
"matchGraph": {
"timesMatched": 142,
"successRate": 0.87,
"topIntents": ["code editor", "AI coding", "cursor alternative"]
},
"compositeScore": 78
}
],
"matchCount": 5,
"graphSignal": {
"gapDetected": false,
"queryId": "api_1713456789_abc123"
},
"_links": {
"self": "https://unfragile.ai/api/v1/search?q=best+code+editor+with+AI",
"schema": "https://unfragile.ai/schema",
"hub": "https://unfragile.ai/hub"
}
}Trust and Protocol Endpoints
These endpoints expose the trust layer directly for agents and enterprise systems. Use them when the question is not only "what matches?" but "is this artifact safe, current, and appropriate for this capability?"
GET /api/v1/resolve
Capability DNS resolver. Pass a `capability://...` URI or natural-language capability and receive ranked artifacts with constraints, risk, trust, and optional passports.
curl "https://unfragile.ai/api/v1/resolve?capability=capability://database.postgres.query.readonly&passport=true"GET /api/v1/match
Trust-first search. Same graph as search, but Match Proof is always returned.
curl "https://unfragile.ai/api/v1/match?q=read-only+postgres+mcp&limit=3"GET /api/v1/verify?slug=…
Artifact trust check by slug, with Match Proof, maintenance signals, and community data. For verify-before-invoke (resolve an install target → signed verdict + audit record), use POST /api/v1/verify above.
curl "https://unfragile.ai/api/v1/verify?slug=cursor"GET /api/v1/passport/[slug]
Agent-readable trust passport: artifact identity, capability URIs, permissions, data access risk, known failure modes, observed outcomes, and UnfragileRank breakdown.
curl "https://unfragile.ai/api/v1/passport/cursor"The response wraps the passport so HATEOAS links stay outside the signed bytes:
{
"passport": {
/* the canonical, signed passport object */
"unfragile": { /* identity, capabilities, risk, outcomes, rank */ },
"signature": "<Ed25519 base64>",
"signedAt": "2026-05-24T...Z",
"signedBy": "unfragile.ai",
"version": 1
},
"_links": {
"self": "https://unfragile.ai/api/v1/passport/cursor",
"verify": "https://unfragile.ai/api/v1/verify?slug=cursor",
"publicKey": "https://unfragile.ai/api/v1/trust-passport-public-key",
"spec": "https://unfragile.ai/trust",
"schema": "https://unfragile.ai/schema.json"
}
}Verify response.passport — NOT the whole body. The signature covers only the passport object; _links live outside it. The resolvePOST embeds this same signed object as each item's trust.
GET /api/v1/trust-passport-public-key
The Ed25519 public key for verifying signed passports offline. Returns{ publicKey, algorithm: "ed25519", issuer, version }. Cache it aggressively (24h public, 7d stale-while-revalidate).
curl "https://unfragile.ai/api/v1/trust-passport-public-key"GET /schema.json
Downloadable JSON Schema for the Unfragile capability manifest and trust passport.
curl "https://unfragile.ai/schema.json"Verifying a Trust Passport
Passports are signed with Ed25519 over a deterministic JSON canonicalization (sorted keys). Verification is fully offline — no roundtrip to Unfragile after you have cached the public key. The canonical recipe:
- Fetch the passport and read
response.passport(from/api/v1/passport/[slug], or the per-itemtrustfrom/api/v1/resolve). - Fetch the base64 public key from
/api/v1/trust-passport-public-key(cache it 24h). - Detach
signature,signedAt,signedBy,versionfrom the passport. - Canonicalize the remaining object with sorted keys (e.g.
safe-stable-stringify) and UTF-8 encode. ed25519.verify(signature, canonicalBytes, publicKey).
import * as ed from "@noble/ed25519";
import { sha512 } from "@noble/hashes/sha2.js";
import stringify from "safe-stable-stringify";
ed.hashes.sha512 = sha512; // @noble/ed25519 v2 needs the hash injected
// 1. Fetch the passport — verify response.passport, NOT the whole body.
const { passport } = await (
await fetch("https://unfragile.ai/api/v1/passport/cursor")
).json();
// 2. Fetch + cache the public key (base64, 32-byte raw Ed25519).
const { publicKey } = await (
await fetch("https://unfragile.ai/api/v1/trust-passport-public-key")
).json();
// 3. Detach the signing envelope; canonicalize the bare payload.
const { signature, signedAt, signedBy, version, ...bare } = passport;
const canonical = new TextEncoder().encode(stringify(bare) ?? "{}");
// 4. Verify offline.
const ok = await ed.verifyAsync(
Buffer.from(signature, "base64"),
canonical,
Buffer.from(publicKey, "base64"),
);
console.log(ok ? "trusted" : "TAMPERED — do not invoke");Issuer is always unfragile.ai. A failed verify means the snapshot was altered in transit — do not trust it. Full spec at /trust.
Rate Limits
| Tier | Limit | Window |
|---|---|---|
| Unauthenticated | 60 | per minute per IP |
| With API key | 300 | per minute |
When rate limited, the API returns 429 Too Many Requests with a Retry-After: 60 header.
Artifact Types
Use the type parameter to filter results. Valid types:
productagentmcpapirepomodelframeworkcliextensionworkflowpromptskilldatasetbenchmarkappwebapptemplateplatformfinetuneExamples
Search for MCP servers:
curl "https://unfragile.ai/api/v1/search?q=google+calendar&type=mcp&limit=3"Search for open-source agents:
curl "https://unfragile.ai/api/v1/search?q=autonomous+coding+agent&type=agent"Python integration:
import requests
resp = requests.get("https://unfragile.ai/api/v1/search", params={
"q": "best framework for building AI agents",
"limit": 5,
"source": "my-app"
})
data = resp.json()
for match in data["matches"]:
artifact = match["artifact"]
print(f"{artifact['name']} (rank: {artifact['unfragileRank']})")
for cap in match["capabilities"][:3]:
print(f" - {cap['name']} ({cap['matchScore']})")JavaScript/TypeScript:
const res = await fetch(
"https://unfragile.ai/api/v1/search?" +
new URLSearchParams({ q: "image generation API", limit: "3" })
);
const { matches, graphSignal } = await res.json();
if (graphSignal.gapDetected) {
console.log("No strong matches — submit at unfragile.ai/submit");
}
for (const match of matches) {
console.log(match.artifact.name, match.compositeScore);
}Graph Learning
Every API call generates match records that feed back into the graph. Over time, the graph learns which capabilities solve which intents. The queryId in the response uniquely identifies each search for tracking.
When gapDetected: true, the query had no strong capability matches — this is recorded as a demand signal visible on /gaps.
Streaming Search (SSE)
For the full AI synthesis experience (like the website), use the streaming endpoint:
curl -N -X POST "https://unfragile.ai/api/search" \
-H "Content-Type: application/json" \
-d '{"query": "best AI for building prototypes"}'Returns Server-Sent Events with progressive tool matches and AI synthesis. This is the same pipeline that powers the website search.
Capability Schema and Protocol
The full capability schema — 10 standard categories, 19 artifact types, JSON-LD context — is published at unfragile.ai/schema.
Builders: see /protocol for the open Capability Protocol v1 spec and /docs/protocol for the publishing walkthrough.
Questions? Reach us at hello@unfragile.ai