MCP tools
This page lists the tools of the Foundation4 Model Context Protocol (MCP) server: the name and description of each tool as an MCP client receives them, every argument with the input schema, the output with the output schema, the annotations, the permissions and the errors. The page also lists the server information of the initialize response and the HTTP errors of the /mcp endpoint. Integrators use this page to configure an MCP client and to interpret tool results. MCP server describes the transport, sessions, authentication and limits.
Server information
The initialize response returns the following server information:
| Field | Value | Description |
|---|---|---|
protocolVersion | The revision named in the request, or 2025-11-25 | The server supports the revisions 2024-11-05, 2025-03-26, 2025-06-18, 2025-11-25 and 2026-07-28. A request for any other revision receives 2025-11-25. |
capabilities | {"tools": {}} | Tools only. The server sends no list change notifications and declares no resources, prompts, completions or logging. |
serverInfo.name | rmcp | The name of the MCP library that the API server uses, not a Foundation4 name |
serverInfo.version | 3.1.4 | The version of the MCP library, not the Foundation4 release |
instructions | Foundation4.ai | A fixed text. The branding name configuration does not change the text. |
The result of an initialize request with the revision 2025-11-25:
{
"protocolVersion": "2025-11-25",
"capabilities": {"tools": {}},
"serverInfo": {"name": "rmcp", "version": "3.1.4"},
"instructions": "Foundation4.ai"
}
The server also answers ping with an empty result, resources/list and prompts/list with empty lists, and completion/complete with an empty list of values. logging/setLevel returns the JSON-RPC error -32601.
Tool list
tools/list returns the three tools in alphabetical order, in one page without a nextCursor. Each tool definition contains name, description, inputSchema, outputSchema and annotations, and no title. The schemas follow JSON Schema draft 2020-12, as the $schema field of each schema states.
| Tool | Description sent to the client |
|---|---|
get_pipeline_classifications | Retrieve a list of document classifications for a particular pipeline |
get_pipelines | Retrieve a list of available Pipelines |
search_knowledge | Perform a search across a foundation4 pipeline. Returns ranked fragments with scores, source document IDs, and classification. |
The annotations describe the effect of each tool. MCP clients treat annotations as hints, for example to decide whether a call needs the user's confirmation.
| Tool | readOnlyHint | destructiveHint | idempotentHint | openWorldHint |
|---|---|---|---|---|
get_pipeline_classifications | true | false | true | false |
get_pipelines | true | false | false | false |
search_knowledge | true | false | true | false |
Tool results
A successful tool call returns a result object with three fields:
| Field | Type | Description |
|---|---|---|
content | Array | One text block, {"type": "text", "text": "<JSON>"}, whose text is the tool output serialized as a JSON string |
structuredContent | Object | The tool output as a JSON object, described by the outputSchema of the tool |
isError | Boolean | false |
The keys of every object in the tool output appear in alphabetical order, in both content and structuredContent. The MCP server page shows a complete response.
With the protocol revision 2026-07-28, which has no sessions, each request carries the revision in the MCP-Protocol-Version header and carries the revision and the client capabilities in _meta. The following tool call needs no session:
curl -X POST "$FOUNDATION4_URL/mcp" \
-H "x-api-key: $FOUNDATION4_API_KEY" \
-H "x-api-key-secret: $FOUNDATION4_API_SECRET" \
-H "Content-Type: application/json" \
-H "Accept: application/json, text/event-stream" \
-H "MCP-Protocol-Version: 2026-07-28" \
-H "Mcp-Method: tools/call" \
-H "Mcp-Name: get_pipelines" \
-d '{
"jsonrpc": "2.0",
"id": 1,
"method": "tools/call",
"params": {
"name": "get_pipelines",
"arguments": {"query": "support"},
"_meta": {
"io.modelcontextprotocol/protocolVersion": "2026-07-28",
"io.modelcontextprotocol/clientCapabilities": {}
}
}
}'
The response is an event stream with one event and no session identifier. The result object carries the field "resultType": "complete" before content, structuredContent and isError. A request whose _meta lacks io.modelcontextprotocol/clientCapabilities receives HTTP status 400 and the JSON-RPC error -32602 request _meta is missing or has malformed required fields: io.modelcontextprotocol/clientCapabilities.
Tool errors
A failed tool call returns an error in one of two forms. When the arguments do not match the types of the input schema, the response is a result with isError set to true and one text block:
| Cause | Text |
|---|---|
| A required argument is missing | failed to deserialize parameters: missing field `pipeline_id` |
| An argument has the wrong type | failed to deserialize parameters: invalid type: string "5", expected u16 |
type has an undefined value | failed to deserialize parameters: unknown variant `vector`, expected one of `query`, `similarity`, `search`, `hybrid`, `mmr`, `history` |
Arguments that the input schema does not define, such as filters or distance_strategy, are ignored without an error.
When the tool runs and the operation fails, the response is a JSON-RPC error object with code, message and, for some errors, data:
| Code | Meaning | Messages |
|---|---|---|
| -32600 | Invalid request | The parser message of an identifier that is not a universally unique identifier (UUID), such as invalid length: found 3; Embedding model not found; Missing embedding model ID |
| -32602 | Invalid parameters | tool not found, for a tool name that the server does not define |
| -32002 | Resource not found | Pipeline not found, with data set to {"id": "<pipeline id>"} |
| -32603 | Internal error | Every other failure, including permission errors, with a message that describes the failure |
The following response reports a pipeline that does not exist or that the key cannot use:
{
"jsonrpc": "2.0",
"id": 2,
"error": {
"code": -32002,
"message": "Pipeline not found",
"data": {"id": "7d3e9a41-2b6c-4f8d-9e1a-5c0b3f6a8d27"}
}
}
HTTP errors
The /mcp endpoint returns the following HTTP errors before a tool runs. Except for status 401 and the _meta error of revision 2026-07-28, which return JSON, the body is plain text, not the JSON error body of the REST API.
| Status | Body | Cause |
|---|---|---|
| 400 | Bad Request: Session ID is required | A GET or DELETE request without the Mcp-Session-Id header |
| 400 | Bad Request: Unsupported MCP-Protocol-Version: <value> | The MCP-Protocol-Version header names a revision that the server does not support |
| 400 | JSON-RPC error -32602 request _meta is missing or has malformed required fields: <field> | A request with the revision 2026-07-28 whose _meta lacks a required field, such as io.modelcontextprotocol/clientCapabilities |
| 401 | JSON error body, such as Unauthorized: No API Key specified. | The API key headers are missing or invalid, as described in Errors |
| 403 | Forbidden: Host header is not allowed | The Host header names a host other than localhost, 127.0.0.1 or ::1 |
| 404 | Not Found: Session not found | The Mcp-Session-Id header names an unknown or ended session, or a session of another API server replica |
| 404 | Empty | A path under /mcp, such as /mcp/ |
| 405 | Method Not Allowed | A method other than GET, POST and DELETE. The Allow header lists the three methods. |
| 406 | Not Acceptable: Client must accept both application/json and text/event-stream | The Accept header of a POST request does not list both types |
| 406 | Not Acceptable: Client must accept text/event-stream | The Accept header of a GET request does not list text/event-stream |
| 413 | Payload Too Large: request body exceeds 4194304 bytes | The body is larger than 4 MiB |
| 415 | Unsupported Media Type: Content-Type must be application/json | The Content-Type header is not application/json |
| 415 | fail to deserialize request body <reason> | The body is not a JSON-RPC message |
| 422 | Unexpected message, expect initialize request | A request other than initialize without the Mcp-Session-Id header |
get_pipelines
get_pipelines lists the pipelines that the API key can read, ordered by pipeline identifier, with offset pagination. The tool corresponds to GET /pipelines with the name$contains filter.
| Argument | Type | Required | Default | Description |
|---|---|---|---|---|
limit | Integer, 0 or greater, or null | No | 10 | The maximum number of pipelines to return. A value of 0 returns no pipelines. No upper limit applies. |
offset | Integer, 0 or greater, or null | No | 0 | The number of pipelines to skip |
query | String or null | No | None | Returns only the pipelines whose name contains the text, case-sensitive. In the text, % matches any sequence of characters and _ matches any single character. |
The call can omit arguments entirely. The output object has one field, results, an array of pipelines with the following fields:
| Field | Type | Description |
|---|---|---|
pipeline_id | String | The pipeline identifier |
name | String | The pipeline name |
description | String or null | The pipeline description |
embedding_model_id | String or null | The pipeline's vector embedding identifier, which the REST API returns as default_vector_embedding_id. The value is not an embedding model identifier and is not accepted as the embedding_model_id argument of search_knowledge. |
default_text_splitter_id | String | The identifier of the pipeline's default text splitter |
The output contains no total count and no page information. A client reads the next page with offset increased by limit, until a call returns fewer pipelines than limit.
- Permissions. The tool returns only the pipelines on which the key holds read permission. A key without read permission on any pipeline receives an empty
resultsarray. - Errors. Argument type errors, such as a negative
limit, return a result withisErrorset totrue. A database failure returns error -32603.
Input schema:
{
"$schema": "https://json-schema.org/draft/2020-12/schema",
"properties": {
"limit": {
"description": "the maximum number of pipelines to return, defaults to 10",
"format": "uint",
"minimum": 0,
"type": ["integer", "null"]
},
"offset": {
"description": "the offset for pagination, defaults to 0",
"format": "uint",
"minimum": 0,
"type": ["integer", "null"]
},
"query": {
"description": "an optional search query to filter pipelines by name",
"type": ["string", "null"]
}
},
"type": "object"
}
Output schema:
{
"$defs": {
"Pipeline": {
"properties": {
"default_text_splitter_id": {
"description": "the unique identifier of the default text splitter used by the pipeline",
"type": "string"
},
"description": {"description": "the description of the pipeline", "type": ["string", "null"]},
"embedding_model_id": {
"description": "the unique identifier of the default embedding model used by the pipeline",
"type": ["string", "null"]
},
"name": {"description": "the name of the pipeline", "type": "string"},
"pipeline_id": {"description": "the unique identifier of the pipeline", "type": "string"}
},
"required": ["pipeline_id", "name", "default_text_splitter_id"],
"type": "object"
}
},
"$schema": "https://json-schema.org/draft/2020-12/schema",
"properties": {"results": {"items": {"$ref": "#/$defs/Pipeline"}, "type": "array"}},
"required": ["results"],
"type": "object"
}
The following call reads the first 10 pipelines whose name contains support:
{
"jsonrpc": "2.0",
"id": 3,
"method": "tools/call",
"params": {"name": "get_pipelines", "arguments": {"query": "support", "limit": 10}}
}
The structuredContent of the result for the support-kb pipeline of First search:
{
"results": [
{
"default_text_splitter_id": "019252e9-b4a0-7713-9a69-d701b4f4a2d1",
"description": "Support knowledge base",
"embedding_model_id": "5d1e8c2a-3f4b-4a6c-9e7d-1b2c3d4e5f60",
"name": "support-kb",
"pipeline_id": "c4a7e2d1-6b3f-4f8e-a2d9-7e1b5c3f9a06"
}
]
}
get_pipeline_classifications
get_pipeline_classifications returns the classifications of one pipeline and the inheritance relationships between the classifications. The tool corresponds to GET /pipelines/{id}/classifications and returns the same object.
| Argument | Type | Required | Default | Description |
|---|---|---|---|---|
pipeline_id | String | Yes | None | The pipeline identifier, a UUID |
| Field | Type | Description |
|---|---|---|
classifications | Array of strings | The classifications that the pipeline defines |
hierarchy | Array of pairs of strings | The inheritance relationships. Each pair names a classification and a classification that the first classification inherits. |
Classifications describes inheritance.
- Permissions. The key requires read permission on the pipeline and the classification allow-list
*on the pipeline, as for the REST operation. - Errors. An identifier that is not a UUID returns error -32600 with the parser message. A pipeline that does not exist, or on which the key lacks read permission, returns error -32002
Pipeline not found. A key whose allow-list on the pipeline is not*receives error -32603 with the messageAuthorization error: AccessLevel(READ).
Input schema:
{
"$schema": "https://json-schema.org/draft/2020-12/schema",
"properties": {"pipeline_id": {"description": "the unique identifier of the pipeline", "type": "string"}},
"required": ["pipeline_id"],
"type": "object"
}
Output schema:
{
"$schema": "https://json-schema.org/draft/2020-12/schema",
"properties": {
"classifications": {
"description": "List of classifications associated with the pipeline",
"items": {"type": "string"},
"type": "array"
},
"hierarchy": {
"description": "Hierarchy of classifications (classification, derived classification)",
"items": {
"maxItems": 2,
"minItems": 2,
"prefixItems": [{"type": "string"}, {"type": "string"}],
"type": "array"
},
"type": "array"
}
},
"required": ["classifications", "hierarchy"],
"type": "object"
}
The structuredContent of the result for the support-kb pipeline of First search, which defines the classifications public and internal, where internal inherits public. The tool returns the same object as GET /pipelines/{id}/classifications, in the same order:
{
"classifications": ["internal", "public"],
"hierarchy": [["internal", "public"]]
}
search_knowledge
search_knowledge runs a similarity, maximal marginal relevance (MMR) or full-text search on one pipeline and returns the ranked fragments. The tool corresponds to POST /pipelines/{id}/search, without metadata filters and without a distance strategy.
| Argument | Type | Required | Default | Description |
|---|---|---|---|---|
pipeline_id | String | Yes | None | The pipeline identifier, a UUID |
embedding_model_id | String or null | No | The pipeline's default embedding model | The identifier of an embedding model that the pipeline uses: the id field of a model in the embedding_models object of the REST pipeline, the same identifier as params.embedding in REST search |
query | String | Yes | None | The search text |
classifications | Array of strings | Yes | None | The classifications to search, matched hierarchically: each named classification and every classification that the named classification inherits. Names that the pipeline does not define are ignored, and an empty array returns no fragments. |
type | String | Yes | None | The search type: similarity, mmr or search (full-text search). The schema also lists query, hybrid and history, which return errors. |
params | Object | No | The defaults of the search type | The parameters of the search type |
The params object accepts the following fields:
| Parameter | Type | Search types | Default without params | Description |
|---|---|---|---|---|
k | Integer, 0 to 65535 | All | 5 | The number of fragments to return. A value of 0 returns no fragments. |
fetch_k | Integer, 0 to 65535 | mmr | 10 | The number of candidates from which MMR search selects k fragments |
lambda_mult | Number or null | mmr | 0.5 | The balance between relevance (1) and diversity (0) |
threshold | Number or null | All | None | For similarity and MMR search, the maximum distance from the query. For full-text search, the minimum rank. |
embedding | String or null | similarity, mmr | None | Accepted and ignored. The embedding model comes from the embedding_model_id argument. |
When the call includes params, a k or fetch_k that params omits takes the value 0, as the "default": 0 of the schema states, and the search returns no fragments. A lambda_mult that params omits takes the value 0.5. Search requests describes each parameter in detail.
The tool processes a call in the following order:
- Pipeline. The tool reads the pipeline with the key's read and execute permissions.
- Embedding model. The tool selects the embedding model named by
embedding_model_id, or the pipeline's default embedding model. A call on a pipeline without an embedding model, such as a full-text-only pipeline, stops here with the errorMissing embedding model ID. - Query embedding. The tool converts the query into a vector with the embedding model, for every search type, including full-text search and the types that return errors.
- Search. The tool runs the search of
typewith thecosinedistance strategy, the hierarchical classifications and no metadata filter.
The output object has one field, results, an array of fragments ordered as in REST search: by ascending distance for similarity and MMR search, and by descending rank for full-text search.
| Field | Type | Description |
|---|---|---|
id | String | The fragment identifier |
classification | String | The classification of the fragment's document |
metadata | Object | The metadata of the fragment's document |
document_id | String | The identifier of the document |
page_content | String | The decrypted text of the fragment. The field is absent when the text is empty. |
version | Integer | The document version, in microseconds since the Unix epoch |
expired_at | String or null | Always null in search results |
embedding | Array of numbers | Defined in the schema, never present in search results |
score | Number | The distance for similarity and MMR search, or the rank for full-text search |
order_id | Integer | The position of the fragment within the document version, starting at 0 |
- Permissions. The key requires read and execute permission on the pipeline, as for REST search.
- Errors. The following table lists the errors of the tool in addition to the argument errors described in Tool errors.
| Code | Message | Cause |
|---|---|---|
| -32600 | The parser message, such as invalid length: found 3 | pipeline_id or embedding_model_id is not a UUID |
| -32002 | Pipeline not found | The pipeline does not exist, or the key lacks read and execute permission on the pipeline |
| -32600 | Embedding model not found | embedding_model_id names a model that the pipeline does not use, including the embedding_model_id value of the pipeline listing |
| -32600 | Missing embedding model ID | The call omits embedding_model_id and the pipeline has no default embedding model. A full-text-only pipeline returns this error for every search type, including search. |
| -32603 | A message that describes the failure | The embedding model could not convert the query into a vector |
| -32603 | Hybrid placeholder is not implemented yet | type is hybrid. data holds the parsed parameters, nested as {"params": {"params": {...}}}. |
| -32603 | History placeholder is not implemented yet | type is history. data holds the parsed parameters, as for hybrid. |
| -32603 | Invalid search type or parameters | type is query |
| -32603 | A message that describes the failure | type is search on a pipeline without full-text search, or another operation failure |
Input schema. The oneOf list defines type and params, and each Params definition names the parameter object of one search type:
{
"$defs": {
"Params": {
"properties": {"params": {"$ref": "#/$defs/PlaceholderParameterSimilarity"}},
"type": "object"
},
"Params2": {"properties": {"params": {"$ref": "#/$defs/PlaceholderParameterSearch"}}, "type": "object"},
"Params3": {"properties": {"params": {"$ref": "#/$defs/PlaceholderParameterHybrid"}}, "type": "object"},
"Params4": {"properties": {"params": {"$ref": "#/$defs/PlaceholderParameterMmr"}}, "type": "object"},
"Params5": {
"properties": {"params": {"$ref": "#/$defs/PlaceholderParameterHistory"}},
"type": "object"
},
"PlaceholderParameterHistory": {
"properties": {
"k": {"default": 0, "format": "uint16", "maximum": 65535, "minimum": 0, "type": "integer"}
},
"type": "object"
},
"PlaceholderParameterHybrid": {
"properties": {
"embedding": {"default": null, "format": "uuid", "type": ["string", "null"]},
"k": {"default": 0, "format": "uint16", "maximum": 65535, "minimum": 0, "type": "integer"}
},
"type": "object"
},
"PlaceholderParameterMmr": {
"properties": {
"embedding": {"default": null, "format": "uuid", "type": ["string", "null"]},
"fetch_k": {"default": 0, "format": "uint16", "maximum": 65535, "minimum": 0, "type": "integer"},
"k": {"default": 0, "format": "uint16", "maximum": 65535, "minimum": 0, "type": "integer"},
"lambda_mult": {"default": null, "format": "double", "type": ["number", "null"]},
"threshold": {"default": null, "format": "double", "type": ["number", "null"]}
},
"type": "object"
},
"PlaceholderParameterSearch": {
"properties": {
"k": {"default": 0, "format": "uint16", "maximum": 65535, "minimum": 0, "type": "integer"},
"threshold": {"default": null, "format": "double", "type": ["number", "null"]}
},
"type": "object"
},
"PlaceholderParameterSimilarity": {
"properties": {
"embedding": {"default": null, "format": "uuid", "type": ["string", "null"]},
"k": {"default": 0, "format": "uint16", "maximum": 65535, "minimum": 0, "type": "integer"},
"threshold": {"default": null, "format": "double", "type": ["number", "null"]}
},
"type": "object"
}
},
"$schema": "https://json-schema.org/draft/2020-12/schema",
"oneOf": [
{
"description": "Query placeholder.",
"properties": {"type": {"const": "query", "type": "string"}},
"required": ["type"],
"type": "object"
},
{
"$ref": "#/$defs/Params",
"description": "Similarity placeholder.",
"properties": {"type": {"const": "similarity", "type": "string"}},
"required": ["type"],
"type": "object"
},
{
"$ref": "#/$defs/Params2",
"description": "Search placeholder.",
"properties": {"type": {"const": "search", "type": "string"}},
"required": ["type"],
"type": "object"
},
{
"$ref": "#/$defs/Params3",
"description": "Hybrid placeholder.",
"properties": {"type": {"const": "hybrid", "type": "string"}},
"required": ["type"],
"type": "object"
},
{
"$ref": "#/$defs/Params4",
"description": "MMR placeholder.",
"properties": {"type": {"const": "mmr", "type": "string"}},
"required": ["type"],
"type": "object"
},
{
"$ref": "#/$defs/Params5",
"description": "History placeholder.",
"properties": {"type": {"const": "history", "type": "string"}},
"required": ["type"],
"type": "object"
}
],
"properties": {
"classifications": {
"description": "the classifications to use for the search results",
"items": {"type": "string"},
"type": "array"
},
"embedding_model_id": {
"description": "the unique identifier of the embedding model to use for the search",
"type": ["string", "null"]
},
"pipeline_id": {"description": "the unique identifier of the pipeline", "type": "string"},
"query": {"description": "the search query for the pipeline", "type": "string"}
},
"required": ["pipeline_id", "query", "classifications"],
"type": "object"
}
Output schema:
{
"$defs": {
"Fragment": {
"properties": {
"classification": {"description": "Classification of the document fragment", "type": "string"},
"document_id": {
"description": "Document unique identifier associated with the fragment",
"type": "string"
},
"embedding": {
"description": "Embedding of the document fragment",
"items": {"format": "double", "type": "number"},
"type": ["array", "null"]
},
"expired_at": {
"description": "Expiration date of the document fragment (if applicable)",
"format": "date-time",
"type": ["string", "null"]
},
"id": {"description": "Unique identifier of the document fragment", "type": "string"},
"metadata": {"description": "Metadata associated with the fragment"},
"order_id": {
"description": "Order id of the fragment within the document",
"format": "int64",
"type": "integer"
},
"page_content": {"description": "Content", "type": "string"},
"score": {"description": "Score if available", "format": "double", "type": ["number", "null"]},
"version": {
"description": "Version of the document fragment",
"format": "int64",
"type": "integer"
}
},
"required": ["id", "classification", "metadata", "document_id", "page_content", "version", "order_id"],
"type": "object"
}
},
"$schema": "https://json-schema.org/draft/2020-12/schema",
"properties": {"results": {"items": {"$ref": "#/$defs/Fragment"}, "type": "array"}},
"required": ["results"],
"type": "object"
}
The following call runs an MMR search for 5 fragments from 20 candidates:
{
"jsonrpc": "2.0",
"id": 4,
"method": "tools/call",
"params": {
"name": "search_knowledge",
"arguments": {
"pipeline_id": "c4a7e2d1-6b3f-4f8e-a2d9-7e1b5c3f9a06",
"query": "How do I rotate the database credentials?",
"classifications": ["internal"],
"type": "mmr",
"params": {"k": 5, "fetch_k": 20, "lambda_mult": 0.5}
}
}
}
The structuredContent of the result for the support-kb pipeline of First search. The pipeline holds no document about database credentials, so the search returns the three fragments of the pipeline by ascending distance. A threshold in params drops fragments beyond a given distance.
{
"results": [
{
"classification": "public",
"document_id": "01a0ed0d-cf82-7c3d-8e4f-5a6b7c8d9e0f",
"expired_at": null,
"id": "01a0ed0d-d291-7c5d-8e4f-3a2b1c0d9e8f",
"metadata": {"product": "accounts"},
"order_id": 0,
"page_content": "To reset a password, open Settings, choose Security and select Reset password. A reset link is sent to the registered email address and expires after 30 minutes.",
"score": 0.6850275409090324,
"version": 1790683500418273
},
{
"classification": "internal",
"document_id": "01a0ed0d-d75f-7d5e-8f60-718293a4b5c6",
"expired_at": null,
"id": "01a0ed0d-d814-7d6c-8b5a-4c3d2e1f0a9b",
"metadata": {"product": "billing"},
"order_id": 0,
"page_content": "Invoices are generated on the first day of each month. Finance staff can export invoices as PDF or CSV files from the Billing page.",
"score": 0.8752695693762373,
"version": 1790683502431906
},
{
"classification": "internal",
"document_id": "01a0ed0d-df3f-7f80-9a1b-2c3d4e5f6a7b",
"expired_at": null,
"id": "01a0ed0d-e007-7c3d-8e4f-6a7b8c9d0e1f",
"metadata": {"product": "billing"},
"order_id": 0,
"page_content": "Refunds for annual plans are prorated. Support agents must record the refund reason in the ticket before approving a refund.",
"score": 1.0389346220209017,
"version": 1790683504447128
}
]
}