Changelog

Stay up to date with all the latest features, improvements, and bug fixes.


Built-in MCP Server & Per-API Agent Visibility

Every Flux API prefix now exposes a built-in Model Context Protocol server alongside its REST endpoints, and two new governance toggles let you control which APIs are discoverable by AI agents. Together they make Flux APIs directly usable by Claude, ChatGPT, the OpenAI Responses API, Cursor, and any MCP-compatible client — without writing a custom tool server or maintaining a second access-control surface.

Flux API

  • New endpoint: GET | POST | DELETE /{api_prefix}/_mcp — per-API MCP server over Streamable HTTP (2025-03-26). Publishes a fixed five-tool catalog (discover, get_schema, get_one, list, search) scoped to the connected folders of the prefix. The search tool exposes hybrid retrieval (vector + full-text + structured filters) as a single call. See MCP Server reference.
  • Same auth and permissions as the REST surface: is_auth_required controls anonymous access, per-folder allowed_methods controls which tools are available per folder, Flux API key roles apply identically.

Management API

  • New fields on the API object (returned by GET, accepted by POST and PATCH):
    • mcp_enabled (boolean, default true) — when false, the /{api_prefix}/_mcp endpoint returns 404
    • router_introspection_enabled (boolean, default true) — when false, the /{api_prefix}/_router endpoint returns 404
  • Both fields are independent policy switches. The data routes (/{folder}, /{folder}/{key}, /{folder}/_search) are never affected.
  • Both fields use strict JSON-boolean validation — strings like "true", integers, and null are rejected with 422.
  • PATCH /v1/{env}/api/{api}/ supports single-field updates: {"mcp_enabled": false} works without re-sending the entire API object.
  • Both fields are captured in the API delete-event audit snapshot.

Documentation

  • New concept page: Agent-Native Flux APIs — what "agent-native" means here, the three introspection endpoints, the differentiators vs. hand-written MCP servers, and a per-prefix governance model.
  • New guides: Connect Claude and Connect ChatGPT and OpenAI.
  • LLM Integrations now lists "MCP Server Connection" as a fourth integration pattern alongside Direct API, LangChain Retriever, and Agent Tool.

Rollout note

Router items written before this release lack the agent_features block in DynamoDB; the Flux API treats a missing block as defaults-on. Items refresh automatically on the next router-build trigger (any API or folder edit). No data migration is required.

Search Metadata & Default Threshold

The Flux _search endpoint now returns a metadata object in every response, showing the effective parameters that were used — including server-side defaults.

"metadata": {
  "search_mode": "vector",
  "limit": 100,
  "vector_search_enabled": true,
  "top_k": 10,
  "similarity_threshold": 0.4
}

The metadata shape varies by search mode. See the Search API reference for the full list of fields per mode.

LangChain Integration 0.3.1

Fixed a bug where vector search modes did not pass limit to the Flux API, causing the top_k parameter to have no effect on the number of returned documents.

The package now conforms to LangChain integration standards and passes the official RetrieversIntegrationTests suite.

pip install langchain-foxnose==0.3.1

Vector Search in Python & TypeScript SDKs

Both official SDKs now have typed models and convenience methods for all Flux vector search modes: vector_search, vector_field_search, hybrid_search, and boosted_search.

Python SDK 0.5.0

  • New flux.models module: SearchMode, VectorSearch, VectorFieldSearch, VectorBoostConfig, HybridConfig, SearchRequest with cross-field validation
  • Convenience methods on FluxClient / AsyncFluxClient with **extra_body pass-through for where, sort, etc.
results = client.hybrid_search(
    "articles",
    query="ML applications",
    find_text={"query": "machine learning"},
    vector_weight=0.7,
    text_weight=0.3,
)

TypeScript SDK 0.3.0

  • New types: SearchMode, VectorSearch, VectorFieldSearch, VectorBoostConfig, HybridConfig, SearchRequest with buildSearchBody() runtime validation
  • Convenience methods on FluxClient with extra parameter forwarding via rest spread
const results = await client.hybridSearch('articles', {
  query: 'ML applications',
  findText: { query: 'machine learning' },
  vectorWeight: 0.7,
  textWeight: 0.3,
});

Vector Fields & Custom Vector Search

FoxNose now supports a full workflow for custom embeddings: you can define vector fields in Management API, store model-generated vectors directly in resources, and search them in Flux with vector_field_search.

This unlocks semantic experiences beyond classic text search, including voice/speaker matching, image similarity, recommendation and ranking scenarios, while keeping search behavior explicit and predictable in vector and vector_boosted modes. For custom vector search, the distance metric is cosine only.

Management API

  • New field type: vector
  • Supported dimensions: 256, 384, 768, 1024, 1536

Flux API

  • New search payload: vector_field_search
  • Supported parameters: field, query_vector, top_k, similarity_threshold
  • vector_field_search is supported with search_mode="vector" and search_mode="vector_boosted"
  • vector_field_search is not supported with search_mode="text" or search_mode="hybrid"
  • vector_field_search and vector_search are mutually exclusive
  • Distance metric for vector field search: cosine only

TypeScript SDK 0.2.0

Support for Flux API introspection and route-level descriptions on API folder connections.

New: Flux introspection methods

  • FluxClient.getRouter() — calls GET /{api_prefix}/_router
  • FluxClient.getSchema(folderPath) — calls GET /{api_prefix}/{folder_path}/_schema
const router = await fluxClient.getRouter();
const schema = await fluxClient.getSchema('content/articles');

Updated: API folder connection methods

  • ManagementClient.addApiFolder() and updateApiFolder() now accept optional route descriptions:
    • descriptionGetOne
    • descriptionGetMany
    • descriptionSearch
    • descriptionSchema
const connection = await managementClient.addApiFolder(apiKey, folderKey, {
  allowedMethods: ['get_many', 'get_one'],
  descriptionGetOne: 'Get one article by key',
  descriptionGetMany: 'List published articles',
  descriptionSearch: 'Search published articles',
  descriptionSchema: 'Read article schema',
});

Updated model

  • APIFolderSummary now includes all description_* fields from Management API responses

Python SDK 0.4.0

Support for Flux API introspection and route-level descriptions on API folder connections.

New: Flux introspection methods

  • FluxClient.get_router() / AsyncFluxClient.get_router() — calls GET /{api_prefix}/_router
  • FluxClient.get_schema(folder_path) / AsyncFluxClient.get_schema(folder_path) — calls GET /{api_prefix}/{folder_path}/_schema
router = flux_client.get_router()
schema = flux_client.get_schema("content/articles")

Updated: API folder connection methods

  • ManagementClient.add_api_folder() and update_api_folder() now accept optional route descriptions:
    • description_get_one
    • description_get_many
    • description_search
    • description_schema
  • Same signature updates are available on AsyncManagementClient
connection = management_client.add_api_folder(
    api_key,
    folder_key,
    allowed_methods=["get_many", "get_one"],
    description_get_one="Get one article by key",
    description_get_many="List published articles",
    description_search="Search published articles",
    description_schema="Read article schema",
)

Updated model

  • APIFolderSummary now includes all description_* fields from Management API responses

Flux API Introspection Updates

New introspection capabilities for Flux APIs to improve runtime discovery for users, MCP servers, and LLM agents.

Flux API

  • New endpoint: GET /{api_prefix}/_router — returns a flat route catalog with method, path, action, scope, path params, query params, request body contract, and response shape
  • New endpoint: GET /{api_prefix}/{folder_path}/_schema — returns live JSON Schema and route metadata for the target folder path
  • /_schema now includes searchable metadata:
    • searchable_fields — fields available for filtering/search
    • non_searchable_fields — fields present in schema but not indexed for search

Management API

  • Folder-to-API connection supports per-action route descriptions:
    • description_get_many
    • description_get_one
    • description_search
    • description_schema
  • These descriptions are used by Flux /_router for each action route

LangChain.js Integration 0.1.0

Initial release of the official LangChain.js integration for FoxNose.

Features

  • FoxNoseRetriever — LangChain BaseRetriever backed by FoxNose Flux search with text, vector, hybrid, and vector-boosted modes
  • FoxNoseLoaderBaseDocumentLoader with cursor-based pagination and loadLazy() async generator for memory-efficient bulk loading
  • createFoxNoseTool — factory that wraps retrieval as a DynamicStructuredTool for LLM agents
  • Flexible content mapping: single field, multiple fields, or custom mapper
  • Metadata control: whitelist, blacklist, system metadata toggle
  • Structured filtering via where parameter
  • Dual output: ESM and CommonJS with full TypeScript declarations

Installation

npm install @foxnose/langchain @foxnose/sdk @langchain/core

Quick Start

import { FluxClient, SimpleKeyAuth } from '@foxnose/sdk';
import { FoxNoseRetriever } from '@foxnose/langchain';

const client = new FluxClient({
  baseUrl: 'https://your-env.fxns.io',
  apiPrefix: 'content',
  auth: new SimpleKeyAuth('YOUR_PUBLIC_KEY', 'YOUR_SECRET_KEY'),
});

const retriever = new FoxNoseRetriever({
  client,
  folderPath: 'knowledge-base',
  pageContentField: 'body',
  searchMode: 'hybrid',
});

const docs = await retriever.invoke('how to build AI applications');

Links

TypeScript SDK 0.1.0

Initial release of the official FoxNose TypeScript SDK.

Features

  • ManagementClient — full coverage of Management API v1: folders, components, resources, revisions, roles, API keys, environments, projects, and more
  • FluxClient — content delivery: list resources, get resource, search with text/vector/hybrid modes
  • Four auth strategies — Anonymous, JWT, Simple key, and Secure (ECDSA P-256)
  • Automatic retries — exponential backoff with jitter and Retry-After support
  • Batch upsert — concurrent resource upserts with configurable maxConcurrency and progress callback
  • Zero dependencies — built on native fetch (Node 18+)
  • Dual output — ESM and CommonJS with full TypeScript declarations

Installation

npm install @foxnose/sdk

Quick Start

import { FluxClient, SimpleKeyAuth } from '@foxnose/sdk';

const client = new FluxClient({
  baseUrl: 'https://your-env.fxns.io',
  apiPrefix: 'content',
  auth: new SimpleKeyAuth('YOUR_PUBLIC_KEY', 'YOUR_SECRET_KEY'),
});

const resources = await client.listResources('articles');

const results = await client.search('articles', {
  search_mode: 'hybrid',
  vector_search: { query: 'how to build AI applications', top_k: 5 },
});

client.close();

Links

Resource External IDs & Upsert API

New external_id field on resources enables idempotent syncing from external systems.

Upsert by external_id

  • New endpoint: PUT /v1/:env/folders/:folder/resources/?external_id=<value>
  • Creates a new resource if the external_id doesn't exist in the folder, or creates a new revision if it does
  • Returns 201 Created, 200 OK, or 202 Accepted (async mode)
  • Supports all standard resource options: name, mode, resource_owner, validate_data, component

external_id on resources

  • Optional identifier — allowed characters: a-z A-Z 0-9 - _ / ., max 255 characters
  • Can be set during POST creation or PUT upsert
  • POST returns 409 external_id_conflict if the ID is already taken in the folder
  • Returned in the resource object as external_id (null when not set)

Improved error handling

  • Non-GET requests (POST, PUT, PATCH, DELETE) to URLs without a trailing slash now return 422 trailing_slash_required instead of 500
  • GET requests without a trailing slash continue to redirect via 301

Endpoints

  • PUT /v1/:env/folders/:folder/resources/?external_id=<value>Upsert Resource
  • POST /v1/:env/folders/:folder/resources/Create Resource (now accepts optional external_id)

Python SDK 0.3.0

Full support for external_id and upsert operations, including concurrent batch upserts.

New: upsert_resource()

  • Creates a resource if the external_id doesn't exist, or creates a new revision if it does
  • Uses PUT /folders/:folder/resources/?external_id=<value> under the hood
folder = client.get_folder_by_path("content/blog-posts")

resource = client.upsert_resource(
    folder,
    {"title": "Hello World", "body": "..."},
    external_id="post-42",
)

New: batch_upsert_resources()

  • Upserts multiple resources in parallel with configurable concurrency
  • Collects successes and failures into a BatchUpsertResult
  • fail_fast=True stops on first error; fail_fast=False (default) processes all items
  • Optional on_progress callback: (completed_count, total_count)
from foxnose_sdk import BatchUpsertItem

folder = client.get_folder_by_path("content/articles")

items = [
    BatchUpsertItem(external_id=f"article-{i}", payload={"title": f"Article {i}"})
    for i in range(100)
]

result = client.batch_upsert_resources(
    folder,
    items,
    max_concurrency=10,
    on_progress=lambda done, total: print(f"{done}/{total}"),
)

print(f"OK: {result.success_count}, Failed: {result.failure_count}")

Updated: create_resource()

  • New optional external_id parameter to assign an external ID during creation
folder = client.get_folder_by_path("content/blog-posts")

resource = client.create_resource(
    folder,
    {"title": "New Post"},
    external_id="post-99",
)

New model field

  • ResourceSummary.external_idstr | None, populated from API responses

New types

  • BatchUpsertItem — input container with external_id, payload, and optional component
  • BatchUpsertResult — output with succeeded, failed lists and total, success_count, failure_count, has_failures properties
  • BatchItemError — error details with index, external_id, and exception

Async support

All new methods are available on AsyncManagementClient with identical signatures.

LangChain Integration 0.2.0

Two new components that extend the LangChain integration beyond retrieval.

FoxNoseLoader

  • Bulk document loading from FoxNose folders with cursor-based pagination
  • Memory-efficient lazy_load() for large folders
  • Async support via alazy_load()
  • Filtering, sorting, and configurable batch size

create_foxnose_tool

  • Factory function that wraps FoxNoseRetriever as a LangChain tool for LLM agents
  • Compatible with any LangChain agent framework (langgraph, etc.)
  • Customizable tool name and description
  • Two response formats: plain string or (str, list[Document]) tuple
from langchain_foxnose import FoxNoseLoader, create_foxnose_tool

# Bulk-load all documents from a folder
loader = FoxNoseLoader(
    client=client,
    folder_path="knowledge-base",
    page_content_field="body",
)
docs = loader.load()

# Create a search tool for agents
tool = create_foxnose_tool(
    client=client,
    folder_path="knowledge-base",
    page_content_field="body",
    search_mode="hybrid",
)

Events API

Audit trail for all content changes — now accessible via API and dashboard.

Features

  • Environment Events — track changes to folders, resources, revisions, components, versions, APIs, roles, and API keys
  • Global Events — track changes to users and projects at the organization level
  • Rich filtering by entity type, event type, time range, and related entities
  • Actor information including user details or API key metadata
  • Detailed metadata for each event type with contextual information

Dashboard

  • Activity Log section added to environment dashboard — view and filter environment events
  • Activity Log section added to organization dashboard — view and filter global events

Endpoints

LangChain Integration 0.1.0

Initial release of the official LangChain integration for FoxNose.

Features

  • FoxNoseRetriever — LangChain BaseRetriever backed by FoxNose Flux search
  • Support for all search modes: text, vector, hybrid, and vector-boosted
  • Flexible content mapping: single field, multiple fields, or custom mapper
  • Metadata control: whitelist, blacklist, system metadata toggle
  • Native async support via AsyncFluxClient
  • Structured filtering via where parameter
  • Convenience from_client_params() constructor

Installation

pip install langchain-foxnose

Quick Start

from langchain_openai import ChatOpenAI
from langchain.chains import RetrievalQA
from langchain_foxnose import FoxNoseRetriever

retriever = FoxNoseRetriever.from_client_params(
    base_url="https://7c9h4pwu.fxns.io",
    api_prefix="content",
    public_key="YOUR_PUBLIC_KEY",
    secret_key="YOUR_SECRET_KEY",
    folder="articles",
    search_mode="hybrid",
    content_field="body",
)

qa = RetrievalQA.from_chain_type(
    llm=ChatOpenAI(model="gpt-4o"),
    retriever=retriever,
)

answer = qa.invoke("What are the best practices for API design?")
print(answer["result"])

Python SDK 0.2.0

Management client methods now accept either string keys or corresponding model objects (e.g. FolderSummary, ResourceSummary) wherever a *_key parameter is used. This eliminates the need to manually extract .key from objects returned by the API.

Added

  • Model objects as identifiers — pass objects like FolderSummary or ResourceSummary directly instead of extracting .key
  • _resolve_key() helper for extracting string keys from model objects
  • 13 type aliases for method parameters: FolderRef, ResourceRef, RevisionRef, ComponentRef, SchemaVersionRef, OrgRef, ProjectRef, EnvironmentRef, ManagementRoleRef, FluxRoleRef, ManagementAPIKeyRef, FluxAPIKeyRef, APIRef
from foxnose_sdk.management import ManagementClient
from foxnose_sdk.auth import SimpleKeyAuth

client = ManagementClient(
    base_url="https://api.foxnose.net",
    auth=SimpleKeyAuth("YOUR_PUBLIC_KEY", "YOUR_SECRET_KEY"),
)

# Before 0.2.0 — manually extract .key
folder = client.get_folder("my-folder")
resources = client.list_resources(folder.key)

# With 0.2.0 — pass the object directly
folder = client.get_folder("my-folder")
resources = client.list_resources(folder)

Python SDK 0.1.0

Initial release of the official FoxNose Python SDK.

Features

  • Full support for Flux API v1
  • Sync and async clients
  • Simple and Secure authentication methods
  • Type hints for all methods and responses
  • Built-in error handling

Installation

pip install foxnose-sdk

Quick Start

from foxnose_sdk.flux import FluxClient
from foxnose_sdk.auth import SimpleKeyAuth

client = FluxClient(
    base_url="https://7c9h4pwu.fxns.io",
    api_prefix="content",
    auth=SimpleKeyAuth("YOUR_PUBLIC_KEY", "YOUR_SECRET_KEY"),
)

# List resources
data = client.list_resources("articles")
for article in data["results"]:
    print(f"- {article['data']['title']}")

# Search with filters
data = client.search("articles", body={
    "where": {
        "$": {
            "all_of": [
                {"status__eq": "published"},
                {"category__in": ["tech", "science"]}
            ]
        }
    },
    "limit": 10
})

# Vector search
data = client.search("articles", body={
    "search_mode": "vector",
    "vector_search": {
        "query": "how to build AI applications",
        "top_k": 5,
        "similarity_threshold": 0.7
    }
})

client.close()

Was this page helpful?