Developer Docs
TypeScript SDK · REST API · Model Selection · MCP Server · FNI Badge
All endpoints are free, no authentication required
Quickstart
One end-to-end flow, runnable with no internal knowledge and no API key. The canonical workflow is always the same:
- Search for what you need (
/api/v1/search). - Take the ids from the returned results β never hard-code a catalog id.
- Inspect the evidence for a candidate via its entity response (FNI factors + specs).
- Compare two or more candidates (
/api/v1/compare). - You (the caller/agent) make the final decision. Free2AI returns evidence; it does not choose for you.
Note for REST users: there is no separate REST /explain endpoint. Evidence inspection is the entity response itself β its returned FNI factors and associated notes. (MCP clients have a free2aitools_explain tool; see below.)
Use the TypeScript SDK
Typed TypeScript client (@free2aitools/sdk) that wraps the same REST API β TypeScript types, retries, and typed errors out of the box. See the SDK quickstart below.
Use the REST API
For scripts, apps, and direct HTTP integrations. Plain JSON over HTTPS β curl, Node, Python, anything, with no additional dependency.
Use the MCP server
For MCP-compatible agents and clients (Claude, Cursor, Windsurf, etc.). Same data, exposed as an Agent/tool protocol.
Use the SDK, REST, or MCP according to your integration environment; all three serve the same catalog and the same evidence. None of them route, rank-by-preference, or decide which model you should use. The SDK is a typed REST client, so it follows the REST defaults. Note: the surfaces use different default result limits β MCP search/rank default to 10 results, REST (and therefore the SDK) defaults to 5; all clamp to a max of 20. Pass an explicit limit if you need a specific count.
Official TypeScript SDK
Initial public release — version 0.1.0, available on npm. A typed client for the existing Free2AI public API (same catalog, same evidence); the REST API and MCP server remain fully supported alternatives.
npm install @free2aitools/sdk import { Free2AIClient } from "@free2aitools/sdk";
// No authentication is currently required for the public API.
const client = new Free2AIClient();
// search() returns a typed SearchResponse; `results` is SearchResult[].
const res = await client.search({ q: "code generation", limit: 5 });
for (const r of res.results) {
console.log(r.name, r.fni_score); // real, typed fields
}
// Free2AITools provides structured discovery and evidence;
// the caller or Agent makes the final decision.
No authentication is currently required for the public API. The SDK is a typed REST client, so it follows the REST defaults (search returns 5 results unless you pass limit). Package: @free2aitools/sdk.
curl (bash)
Requires jq. Set F2AI_BASE to override the base URL.
#!/usr/bin/env bash
# Canonical workflow: search -> derive ids from results -> inspect entity ->
# compare candidates -> the CALLER decides. No id is hard-coded; all ids come
# from the search response. Prerequisite: jq (https://jqlang.github.io/jq/).
set -euo pipefail
BASE="${F2AI_BASE:-https://free2aitools.com}"
# 1) Search. --fail-with-body surfaces 4xx/5xx; we branch on the status code.
http_code=$(curl -sS -o /tmp/f2ai_search.json -w '%{http_code}' \
"$BASE/api/v1/search?q=code+generation&limit=5") || true
case "$http_code" in
200) ;; # ok
400) echo "bad request (400) - fix the query"; exit 1 ;;
404) echo "not found (404)"; exit 1 ;;
429|503) echo "transient ($http_code) - retry after Retry-After seconds"; exit 75 ;;
*) echo "server error ($http_code)"; exit 1 ;;
esac
# 2) Derive ids from the result set. Fail honestly if fewer than 2 are returned
# (do NOT silently fall through to an empty compare).
mapfile -t IDS < <(jq -r '.results[].id' /tmp/f2ai_search.json)
if [ "${#IDS[@]}" -lt 2 ]; then
echo "search returned ${#IDS[@]} result(s); need >= 2 to compare. Stopping."
exit 1
fi
# 3) Inspect one candidate (evidence is in the entity response: FNI factors +
# specs). REST has no separate /explain endpoint. URL-encode '/' in the id.
ID_ENC=$(printf '%s' "${IDS[0]}" | jq -sRr @uri)
curl -sS "$BASE/api/v1/entity/$ID_ENC" | jq '.entity.fni.factors'
# 4) Compare the first two candidates side by side.
curl -sS "$BASE/api/v1/compare?ids=${IDS[0]},${IDS[1]}" | jq '.'
# 5) The caller/agent makes the final selection from this evidence.
echo "Review the factors above and choose. Free2AI does not decide for you." JavaScript / TypeScript (Node 18+)
Built-in fetch, no dependencies.
// Node 18+ (built-in fetch) β the direct REST path, no additional dependency.
// You can also use the official TypeScript SDK: npm install @free2aitools/sdk (see the SDK section above).
// Canonical workflow: search -> ids from results -> entity (evidence) ->
// compare -> the caller decides. Retries ONLY 429/503, max 2, honors Retry-After.
const BASE = process.env.F2AI_BASE || "https://free2aitools.com";
async function call(path, { timeoutMs = 10000 } = {}) {
let attempt = 0;
for (;;) {
const ctrl = new AbortController();
const timer = setTimeout(() => ctrl.abort(), timeoutMs);
let res;
try {
res = await fetch(BASE + path, { signal: ctrl.signal });
} finally {
clearTimeout(timer);
}
// Status check BEFORE parsing the body.
if (res.status === 400 || res.status === 404) {
throw new Error(`non-retryable ${res.status} for ${path}`);
}
if ((res.status === 429 || res.status === 503) && attempt < 2) {
const ra = Number(res.headers.get("retry-after"));
const delay = Number.isFinite(ra) && ra > 0 ? ra * 1000 : 500 * (attempt + 1);
await new Promise((r) => setTimeout(r, Math.min(delay, 5000)));
attempt++;
continue;
}
if (!res.ok) throw new Error(`request failed ${res.status} for ${path}`);
return res.json();
}
}
export async function pickCandidates(query = "code generation") {
const search = await call(`/api/v1/search?q=${encodeURIComponent(query)}&limit=5`);
const results = Array.isArray(search.results) ? search.results : [];
if (results.length < 2) {
throw new Error(`need >= 2 results to compare; got ${results.length}`);
}
// Use the ids the server returned. Preserve null (not-measured) vs 0 (measured).
const ids = results.map((r) => r.id);
const entity = await call(`/api/v1/entity/${encodeURIComponent(ids[0])}`);
const factors = entity?.entity?.fni?.factors ?? null; // may be null; no fabrication
const comparison = await call(`/api/v1/compare?ids=${ids[0]},${ids[1]}`);
// The caller/agent reasons over this evidence and makes the final choice.
return { ids, factors, comparison };
} Python (requests)
# python -m pip install requests
# Any standards-compliant HTTP client may be used.
# Canonical workflow: search -> ids from results -> entity (evidence) ->
# compare -> the caller decides. Retries ONLY 429/503, max 2, honors Retry-After.
import os
import time
import requests
BASE = os.environ.get("F2AI_BASE", "https://free2aitools.com")
def call(path, timeout=(5, 10)):
attempt = 0
while True:
resp = requests.get(BASE + path, timeout=timeout)
if resp.status_code in (400, 404):
resp.raise_for_status() # non-retryable client error
if resp.status_code in (429, 503) and attempt < 2:
ra = resp.headers.get("Retry-After")
try:
delay = float(ra) if ra is not None else 0.5 * (attempt + 1)
except ValueError:
delay = 0.5 * (attempt + 1)
time.sleep(min(delay, 5.0))
attempt += 1
continue
resp.raise_for_status() # raises on remaining 5xx; no indefinite retry
return resp.json()
def pick_candidates(query="code generation"):
search = call(f"/api/v1/search?q={requests.utils.quote(query)}&limit=5")
results = search.get("results") or []
if len(results) < 2:
raise RuntimeError(f"need >= 2 results to compare; got {len(results)}")
ids = [r.get("id") for r in results] # use server-returned ids
entity = call(f"/api/v1/entity/{requests.utils.quote(ids[0], safe='')}")
# null-safe: factors may be missing/None; never fabricate a default.
factors = (entity.get("entity") or {}).get("fni", {}).get("factors")
comparison = call(f"/api/v1/compare?ids={ids[0]},{ids[1]}")
# The caller/agent reasons over this evidence and makes the final choice.
return {"ids": ids, "factors": factors, "comparison": comparison} /openapi.json. Point a code generator or an agent at it to consume the API contract directly.
REST API
GET /api/v1/search
Search and rank AI models, tools, datasets, and papers by FNI score.
Parameters
| Param | Type | Default | Description |
|---|---|---|---|
| q | string | - | Search query (required) |
| limit | number | 5 | Maximum results per request (1β20) |
| type | string | all |
Filter by entity type. Canonical values: model, tool, dataset, paper.
Common source-prefixed aliases also accepted: hf-model, gh-model, arxiv-paper, gh-tool, etc. (auto-mapped to canonical).
|
Example
curl "https://free2aitools.com/api/v1/search?q=code+generation&limit=2" Response
{
"version": "fni_v2.0",
"results": [
{
"id": "<id-from-result-1>",
"name": "<name>",
"type": "model",
"fni_score": 87.2
},
{
"id": "<id-from-result-2>",
"name": "<name>",
"type": "model",
"fni_score": 83.5
}
],
"meta": {
"elapsed_ms": 42,
"total": 2
}
}
Search may return a retryable transient 503 under cold-path or fallback budget limits. Retry according to the Retry-After header.
Pagination: page is 1-based and defaults to 1; combine it with limit and use total_count to estimate the remaining pages. The dataset refreshes daily, so results may change between requests; no cursor or snapshot consistency is promised.
POST /api/v1/select
Filter the catalog by declared metadata; returns FNI-ranked entries. Constraints are metadata/heuristic filters, not verified compatibility analysis β the caller is responsible for final model selection.
Request Body (JSON)
{
"task": "text-generation",
"constraints": {
"max_vram_gb": 24,
"license": "commercial"
},
"limit": 5
} Constraints (all optional)
| Field | Type | Description |
|---|---|---|
| task | string | Task name or alias ("llm", "code", "embeddings") |
| max_vram_gb | number | Maximum VRAM in GB |
| max_params_b | number | Maximum parameters in billions |
| license | string | "commercial", "apache-2.0", "mit", or "any" |
| min_context_length | number | Minimum context window (tokens) |
| limit | number | Max results (1-20, default 5) |
curl
curl -X POST https://free2aitools.com/api/v1/select \
-H "Content-Type: application/json" \
-d '{"task":"text-generation","constraints":{"max_vram_gb":24}}' Response
{
"task_interpreted": "text-generation",
"entries": [
{
"rank": 1,
"model_id": "<model_id-from-response>",
"name": "<name>",
"fni_score": 49.3,
"params_billions": 20.87,
"vram_estimate_gb": 17,
"fni_factors": {
"semantic": null,
"semantic_note": "query-time baseline; scored live at search; not a per-entity value",
"authority": 0,
"popularity": 70.5,
"recency": 98.1,
"quality": 65
},
"fni_summary": "FNI 49.3 catalog entry; leading factor recency (98.1); 21B params."
}
]
} GET /api/v1/compare
Side-by-side model comparison with FNI factor decomposition.
Parameters
| Param | Type | Description |
|---|---|---|
| ids | string | Comma-separated entity IDs (2-25). Use model_id from the Select API or id from Search. |
curl (HF-native id form, internal form, or slug β all accepted)
# <ID_1>,<ID_2> = two id values taken from /api/v1/search results. curl "https://free2aitools.com/api/v1/compare?ids=<ID_1>,<ID_2>"
Obtain at least two ids from search first; see Quickstart for a runnable end-to-end flow.
GET /api/v1/entity/:id
Full structured metadata for a single entity. Use this after search to fetch the complete detail you need to make a decision: FNI factors, technical specs, VRAM estimates, license, links, relations.
Accepted id forms
Grammar templates only (<...> are placeholders, not live ids). In practice take the id or slug straight from a /api/v1/search result and pass it back unchanged.
- HuggingFace-native:
<author>/<name> - Bare name (auto-prefixes common sources):
<name> - Internal canonical:
hf-model--<author>--<name> - Slug form (the
slugfield of a search response):<author>--<name>
Case-insensitive. Lookup probes the matching shards in parallel and returns the first hit.
Query parameters
| Param | Default | Description |
|---|---|---|
| include | (empty) | Comma list. include=body adds the rendered README (can be up to 250KB). Default response is lean. |
Status codes
200β entity found404β no entity matches any candidate form (genuine miss; don't retry)503β all probed shards errored (transient infra; retry after a short delay)400 / 500β bad request / unexpected server error
curl (id template β substitute an id obtained from search)
# <ID_FROM_SEARCH> = the id field of a /api/v1/search result (URL-encode '/'). curl "https://free2aitools.com/api/v1/entity/<ID_FROM_SEARCH>"
For a copy-paste runnable version that derives the id automatically, see Quickstart below.
Response shape (lean default)
{
"version": "fni_v2.0",
"entity": {
"id": "<id-from-search>",
"slug": "<slug-from-search>",
"type": "model",
"name": "<name>",
"author": "<author>",
"fni": {
"score": 87.5,
"factors": {
"semantic": null,
"authority": 95,
"popularity": 88,
"recency": 85,
"quality": 80
}
},
"specs": {
"params_billions": 8,
"context_length": 8192,
"vram": {
"fp16_gb": 16
},
"ollama_compatible": true
},
"stats": {
"downloads": 1234567,
"last_modified": "..."
},
"links": {
"detail_url": "...",
"badge_url": "..."
},
"relations": {
"datasets_used": [],
"related": []
}
},
"meta": {
"elapsed_ms": 142,
"candidates_tried": 3
}
} Field semantics: 0 means measured-zero, null means not-measured. Treat them differently when scoring downstream.
/openapi.json (OpenAPI request/response contract), /llms.txt (plain markdown index per llmstxt.org), /.well-known/mcp.json (MCP manifest with tool catalog).
MCP Server
Free2AI exposes an MCP server so AI agents (Claude, Cursor, Windsurf, etc.) can discover and rank AI tools automatically.
free2aitools_search
Search and rank AI tools, models, datasets, and papers by FNI score.
free2aitools_rank
Keyword-search AI entities using the task text as query input. Returns FNI-ranked catalog entries. Does not perform task-fit recommendation or compatibility analysis.
free2aitools_explain
Explain why a specific entity received its FNI ranking score with factor breakdown.
free2aitools_select_model
Filter the catalog by declared metadata; returns FNI-ranked entries with an optional per-entry fni_summary (factual FNI factor/spec facts). Constraints are metadata/heuristic filters, not verified compatibility analysis.
free2aitools_compare
Compare 2-25 AI models side-by-side with FNI factor decomposition.
free2aitools_search first, take the ids from its results, pass those ids to free2aitools_explain for the factor breakdown and to free2aitools_compare, then decide outside Free2AI. Do not pass invented ids; use the ones search returned.
Setup
Claude Desktop / Claude Code
Add to your MCP settings (claude_desktop_config.json or .mcp.json):
{
"mcpServers": {
"free2aitools": {
"url": "https://free2aitools.com/api/mcp",
"transport": "streamable-http"
}
}
} Cursor
Go to Settings > MCP Servers > Add Server, enter:
URL: https://free2aitools.com/api/mcp
Transport: Streamable HTTP Windsurf
Go to Cascade > Plugins > Add MCP Server, enter:
URL: https://free2aitools.com/api/mcp
Transport: Streamable HTTP Any MCP Client / Auto-Discovery
Endpoint: POST https://free2aitools.com/api/mcp
Protocol: JSON-RPC 2.0 (MCP Spec 2025-03-26). Supports initialize, tools/list, tools/call.
Machine-readable server manifest: https://free2aitools.com/.well-known/mcp.json
FNI Badge
Embed a live FNI score badge in your README, docs, or website. The badge updates automatically as scores change.
Endpoint
GET https://free2aitools.com/api/v1/badge/{umid} Returns an SVG image. Color-coded: green (90+), blue (70+), yellow (50+), red (<50). Cached 1 hour at CDN edge.
Markdown (README)
 HTML
<img src="https://free2aitools.com/api/v1/badge/YOUR_UMID" alt="FNI Score" /> id returned by search as the canonical entity identifier for entity, compare, and badge requests. The response also exposes canonical_id, which has the same value. UMID is a separate derived 16-character hexadecimal digest of the canonical ID; callers do not need to compute it for these endpoints.
Open Data
For bulk access and offline analysis, download FNI rankings as Apache Parquet files. Compatible with DuckDB, Pandas, Spark, and any columnar data tool.
View Open Data DownloadsFNI Score
Every entity is ranked by the Free2AITools Nexus Index (FNI) β a composite score from 0 to 99.9 based on five factors:
Trust, Versions & Lifecycle
Security contact
Report a security issue via the GitHub repository's security advisories, or open a GitHub issue. A machine-readable copy is published at /.well-known/security.txt (RFC 9116).
Version domains (distinct, not a single version)
Free2AItools exposes several independent components, each with its own version domain. These are distinct and are not kept in numeric equality β do not assume one number applies to another.
- SDK package (
@free2aitools/sdk):0.1.0 - MCP server:
2.0.1(manifest at/.well-known/mcp.json) - OpenAPI document:
2.0.0(served at/openapi.json) β independent of the MCP server version above - Application / root package:
2.1.0 - FNI / data contract:
fni_v2.0(theversionfield in API/MCP responses)
claude_desktop_config.json / .mcp.json or your client's MCP settings) and restart the client. No server-side de-registration step is required, because nothing about your client is stored.
Build with Free2AI
602,000+ AI entities · FNI-ranked · Updated daily