API Reference

afas_mcp_server

afas_mcp_server: an MCP server that exposes AFAS Profit GetConnectors, UpdateConnectors and metainfo to AI agents.

Modules:

  • client –

    Thin asynchronous client for the AFAS Profit REST services.

  • configuration –

    Runtime configuration for the AFAS MCP server, read from AFAS_* environment variables.

  • filters –

    Filter, sort and paging expressions for GetConnector calls, rendered the way the AFAS REST API expects them.

  • server –

    The MCP server: tools that expose the connectors of one AFAS Profit environment to an AI agent.

  • validation –

    Offline checks of UpdateConnector payloads against the schema AFAS publishes for the connector.

Classes:

  • AfasApiError –

    An HTTP error response from the AFAS REST services, with the Profit error details decoded.

  • AfasClient –

    Asynchronous access to GetConnectors, UpdateConnectors and metainfo of one AFAS environment.

  • AfasError –

    Base class for errors raised by the AFAS client.

  • Environment –

    The kind of AFAS Online environment, which selects the REST hostname.

  • Filter –

    One condition on a GetConnector column.

  • Issue –

    One problem found in a payload.

  • Operator –

    Comparison operators AFAS supports in GetConnector filters, by readable name.

  • Settings –

    Connection and behaviour settings, populated from AFAS_* environment variables or a .env file.

Functions:

  • build_server –

    Create the MCP server for one AFAS environment.

  • validate_element –

    Check an Element payload against an UpdateConnector schema without calling AFAS.

AfasApiError
AfasApiError(
    status_code: int,
    method: str,
    url: str,
    details: dict[str, Any],
)

Bases: AfasError


              flowchart TD
              afas_mcp_server.AfasApiError[AfasApiError]
              afas_mcp_server.client.AfasError[AfasError]

                              afas_mcp_server.client.AfasError --> afas_mcp_server.AfasApiError
                


              click afas_mcp_server.AfasApiError href "" "afas_mcp_server.AfasApiError"
              click afas_mcp_server.client.AfasError href "" "afas_mcp_server.client.AfasError"
            

An HTTP error response from the AFAS REST services, with the Profit error details decoded.

Parameters:

  • status_code
    (int) –

    The HTTP status code.

  • method
    (str) –

    The HTTP method of the failed call.

  • url
    (str) –

    The URL of the failed call.

  • details
    (dict[str, Any]) –

    Error information decoded from the body and the X-PROFIT-ERROR header.

Methods:

  • describe –

    Return a one-line human readable summary of the failure.

describe
describe() -> str

Return a one-line human readable summary of the failure.

AfasClient
AfasClient(
    settings: Settings,
    transport: AsyncBaseTransport | None = None,
)

Asynchronous access to GetConnectors, UpdateConnectors and metainfo of one AFAS environment.

Use it as an async context manager so the underlying HTTP connection pool is closed.

Parameters:

  • settings
    (Settings) –

    Connection settings.

  • transport
    (AsyncBaseTransport | None, default: None ) –

    Optional HTTP transport, used by tests to fake AFAS.

Methods:

  • __aenter__ –

    Enter the context; the client is ready to use as soon as it is constructed.

  • __aexit__ –

    Close the HTTP connection pool.

  • aclose –

    Close the HTTP connection pool.

  • delete –

    Delete one record through an UpdateConnector.

  • describe_get_connector –

    Return the field definitions of a GetConnector.

  • describe_update_connector –

    Return the schema of an UpdateConnector, including nested objects.

  • fetch_rows –

    Return one page of rows from a GetConnector.

  • insert –

    Create records through an UpdateConnector.

  • list_connectors –

    Return the GetConnectors and UpdateConnectors the token may use, as AFAS reports them.

  • profit_version –

    Return the Profit version information, which doubles as a connectivity and token check.

  • request –

    Send one request to AFAS and return its decoded JSON body.

  • update –

    Change existing records through an UpdateConnector.

__aenter__ async
__aenter__() -> Self

Enter the context; the client is ready to use as soon as it is constructed.

__aexit__ async
__aexit__(*exc_info: object) -> None

Close the HTTP connection pool.

aclose async
aclose() -> None

Close the HTTP connection pool.

delete async
delete(
    connector_id: str,
    key_field: str,
    key_value: str | int,
    object_name: str | None = None,
) -> Any

Delete one record through an UpdateConnector.

Parameters:

  • connector_id (str) –

    The UpdateConnector id.

  • key_field (str) –

    The key field, with or without the leading @.

  • key_value (str | int) –

    The key value of the record to delete.

  • object_name (str | None, default: None ) –

    The element to delete from; defaults to the connector itself.

Returns:

  • Any –

    Whatever AFAS returns, often nothing.

describe_get_connector async
describe_get_connector(connector_id: str) -> dict[str, Any]

Return the field definitions of a GetConnector.

Parameters:

  • connector_id (str) –

    The GetConnector id.

Returns:

  • dict[str, Any] –

    The metainfo document with name, description and fields.

describe_update_connector async
describe_update_connector(
    connector_id: str,
) -> dict[str, Any]

Return the schema of an UpdateConnector, including nested objects.

Parameters:

  • connector_id (str) –

    The UpdateConnector id.

Returns:

  • dict[str, Any] –

    The metainfo document with fields and objects.

fetch_rows async
fetch_rows(
    connector_id: str,
    *,
    skip: int = 0,
    take: int | None = None,
    filters: list[Filter] | None = None,
    order_by: list[str] | None = None,
) -> list[dict[str, Any]]

Return one page of rows from a GetConnector.

Parameters:

  • connector_id (str) –

    The GetConnector id.

  • skip (int, default: 0 ) –

    Number of rows to skip.

  • take (int | None, default: None ) –

    Number of rows to return; defaults to the configured page size.

  • filters (list[Filter] | None, default: None ) –

    Conditions to apply.

  • order_by (list[str] | None, default: None ) –

    Sort order; prefix a field with - for descending.

Returns:

  • list[dict[str, Any]] –

    The rows of the page, each a mapping of field id to value.

insert async
insert(
    connector_id: str,
    element: dict[str, Any] | list[dict[str, Any]],
) -> Any

Create records through an UpdateConnector.

Parameters:

Returns:

  • Any –

    Whatever AFAS returns, usually the keys of the created records.

list_connectors async
list_connectors() -> dict[str, Any]

Return the GetConnectors and UpdateConnectors the token may use, as AFAS reports them.

profit_version async
profit_version() -> dict[str, Any]

Return the Profit version information, which doubles as a connectivity and token check.

request async
request(
    method: str,
    path: str,
    *,
    params: dict[str, str] | None = None,
    body: dict[str, Any] | None = None,
) -> Any

Send one request to AFAS and return its decoded JSON body.

Parameters:

  • method (str) –

    HTTP method.

  • path (str) –

    Path relative to the REST services base URL.

  • params (dict[str, str] | None, default: None ) –

    Query parameters.

  • body (dict[str, Any] | None, default: None ) –

    JSON body for POST and PUT.

Returns:

  • Any –

    The decoded JSON response, or None when AFAS sent no body.

Raises:

  • AfasApiError –

    When AFAS answers with an HTTP error status.

update async
update(
    connector_id: str,
    element: dict[str, Any] | list[dict[str, Any]],
) -> Any

Change existing records through an UpdateConnector.

Parameters:

  • connector_id (str) –

    The UpdateConnector id.

  • element (dict[str, Any] | list[dict[str, Any]]) –

    The Element payload, including the @Key entries that identify the records.

Returns:

  • Any –

    Whatever AFAS returns, often nothing.

AfasError

Bases: Exception


              flowchart TD
              afas_mcp_server.AfasError[AfasError]

              

              click afas_mcp_server.AfasError href "" "afas_mcp_server.AfasError"
            

Base class for errors raised by the AFAS client.

Environment

Bases: str, Enum


              flowchart TD
              afas_mcp_server.Environment[Environment]

              

              click afas_mcp_server.Environment href "" "afas_mcp_server.Environment"
            

The kind of AFAS Online environment, which selects the REST hostname.

Attributes:

  • host_prefix (str) –

    The hostname fragment AFAS Online uses for this environment kind.

host_prefix property
host_prefix: str

The hostname fragment AFAS Online uses for this environment kind.

Filter

Bases: BaseModel


              flowchart TD
              afas_mcp_server.Filter[Filter]

              

              click afas_mcp_server.Filter href "" "afas_mcp_server.Filter"
            

One condition on a GetConnector column.

Attributes:

  • rendered_value (str) –

    The value as text, with the wildcards AFAS expects for the text operators.

rendered_value property
rendered_value: str

The value as text, with the wildcards AFAS expects for the text operators.

Issue

Bases: BaseModel


              flowchart TD
              afas_mcp_server.Issue[Issue]

              

              click afas_mcp_server.Issue href "" "afas_mcp_server.Issue"
            

One problem found in a payload.

Operator

Bases: str, Enum


              flowchart TD
              afas_mcp_server.Operator[Operator]

              

              click afas_mcp_server.Operator href "" "afas_mcp_server.Operator"
            

Comparison operators AFAS supports in GetConnector filters, by readable name.

Attributes:

  • code (int) –

    The numeric operatortypes value AFAS uses for this operator.

code property
code: int

The numeric operatortypes value AFAS uses for this operator.

Settings

Bases: BaseSettings


              flowchart TD
              afas_mcp_server.Settings[Settings]

              

              click afas_mcp_server.Settings href "" "afas_mcp_server.Settings"
            

Connection and behaviour settings, populated from AFAS_* environment variables or a .env file.

Either member_id (optionally with environment) or an explicit base_url must be provided.

Methods:

  • check_consistency –

    Reject settings that cannot produce a base URL or a usable log level.

Attributes:

authorization_header property
authorization_header: str

The value of the Authorization header sent with every AFAS call.

python_log_level property
python_log_level: str

The log level as Python's logging module spells it.

rest_base_url property
rest_base_url: str

The REST services base URL, without a trailing slash.

check_consistency
check_consistency() -> Self

Reject settings that cannot produce a base URL or a usable log level.

Returns:

  • Self –

    The validated settings, unchanged.

Raises:

  • ValueError –

    When neither an endpoint nor a known log level is available.

build_server
build_server(
    settings: Settings | None = None,
    transport: AsyncBaseTransport | None = None,
) -> MCPServer

Create the MCP server for one AFAS environment.

Parameters:

  • settings
    (Settings | None, default: None ) –

    Connection settings; read from the environment when omitted.

  • transport
    (AsyncBaseTransport | None, default: None ) –

    Optional HTTP transport for the AFAS client, used by tests to fake AFAS.

Returns:

  • MCPServer –

    A server with the read tools, and the write tools when the settings allow writes.

validate_element
validate_element(
    schema: dict[str, Any], element: object, operation: str
) -> list[Issue]

Check an Element payload against an UpdateConnector schema without calling AFAS.

Parameters:

  • schema
    (dict[str, Any]) –

    The UpdateConnector schema as returned by metainfo/update/{id}.

  • element
    (object) –

    The Element payload that would be sent; a mapping or a list of mappings.

  • operation
    (str) –

    insert or update.

Returns:

  • list[Issue] –

    The problems found; empty when the payload looks valid.

__main__

Command-line entry point, installed as afas-mcp-server and reachable as python -m afas_mcp_server.

Functions:

  • build_parser –

    Describe the command line.

  • configure_logging –

    Log to stderr; stdout belongs to the MCP protocol when running over stdio.

  • load_settings –

    Read the settings, explaining on stderr what is missing when they are invalid.

  • main –

    Run the command line.

  • profit_version –

    Ask AFAS for its version with a short-lived client.

  • run_check –

    Verify the connection and report the outcome.

  • serve –

    Build the server and run it on the requested transport until the client disconnects.

build_parser
build_parser() -> ArgumentParser

Describe the command line.

configure_logging
configure_logging(level: str) -> None

Log to stderr; stdout belongs to the MCP protocol when running over stdio.

load_settings
load_settings() -> Settings | None

Read the settings, explaining on stderr what is missing when they are invalid.

Returns:

  • Settings | None –

    The settings, or None when they could not be validated.

main
main(argv: Sequence[str] | None = None) -> int

Run the command line.

Parameters:

  • argv (Sequence[str] | None, default: None ) –

    Arguments without the program name; defaults to the process arguments.

Returns:

  • int –

    The process exit code.

profit_version async
profit_version(settings: Settings) -> dict[str, Any]

Ask AFAS for its version with a short-lived client.

run_check
run_check(settings: Settings) -> int

Verify the connection and report the outcome.

Parameters:

  • settings (Settings) –

    The connection settings to verify.

Returns:

  • int –

    The process exit code: 0 when AFAS answered, 1 otherwise.

serve
serve(settings: Settings, args: Namespace) -> None

Build the server and run it on the requested transport until the client disconnects.

client

Thin asynchronous client for the AFAS Profit REST services.

Classes:

  • AfasApiError –

    An HTTP error response from the AFAS REST services, with the Profit error details decoded.

  • AfasClient –

    Asynchronous access to GetConnectors, UpdateConnectors and metainfo of one AFAS environment.

  • AfasError –

    Base class for errors raised by the AFAS client.

Functions:

  • connector_path –

    Join path segments under connectors/, percent-encoding everything but @.

  • decode_profit_error_header –

    Decode the base64 X-PROFIT-ERROR header AFAS adds to failed calls.

  • error_details –

    Collect everything AFAS tells us about a failed call.

  • parse_json –

    Return the JSON body of a response, or None when there is none.

  • update_body –

    Wrap an element in the envelope UpdateConnectors expect.

AfasApiError
AfasApiError(
    status_code: int,
    method: str,
    url: str,
    details: dict[str, Any],
)

Bases: AfasError


              flowchart TD
              afas_mcp_server.client.AfasApiError[AfasApiError]
              afas_mcp_server.client.AfasError[AfasError]

                              afas_mcp_server.client.AfasError --> afas_mcp_server.client.AfasApiError
                


              click afas_mcp_server.client.AfasApiError href "" "afas_mcp_server.client.AfasApiError"
              click afas_mcp_server.client.AfasError href "" "afas_mcp_server.client.AfasError"
            

An HTTP error response from the AFAS REST services, with the Profit error details decoded.

Parameters:

  • status_code (int) –

    The HTTP status code.

  • method (str) –

    The HTTP method of the failed call.

  • url (str) –

    The URL of the failed call.

  • details (dict[str, Any]) –

    Error information decoded from the body and the X-PROFIT-ERROR header.

Methods:

  • describe –

    Return a one-line human readable summary of the failure.

describe
describe() -> str

Return a one-line human readable summary of the failure.

AfasClient
AfasClient(
    settings: Settings,
    transport: AsyncBaseTransport | None = None,
)

Asynchronous access to GetConnectors, UpdateConnectors and metainfo of one AFAS environment.

Use it as an async context manager so the underlying HTTP connection pool is closed.

Parameters:

  • settings (Settings) –

    Connection settings.

  • transport (AsyncBaseTransport | None, default: None ) –

    Optional HTTP transport, used by tests to fake AFAS.

Methods:

  • __aenter__ –

    Enter the context; the client is ready to use as soon as it is constructed.

  • __aexit__ –

    Close the HTTP connection pool.

  • aclose –

    Close the HTTP connection pool.

  • delete –

    Delete one record through an UpdateConnector.

  • describe_get_connector –

    Return the field definitions of a GetConnector.

  • describe_update_connector –

    Return the schema of an UpdateConnector, including nested objects.

  • fetch_rows –

    Return one page of rows from a GetConnector.

  • insert –

    Create records through an UpdateConnector.

  • list_connectors –

    Return the GetConnectors and UpdateConnectors the token may use, as AFAS reports them.

  • profit_version –

    Return the Profit version information, which doubles as a connectivity and token check.

  • request –

    Send one request to AFAS and return its decoded JSON body.

  • update –

    Change existing records through an UpdateConnector.

__aenter__ async
__aenter__() -> Self

Enter the context; the client is ready to use as soon as it is constructed.

__aexit__ async
__aexit__(*exc_info: object) -> None

Close the HTTP connection pool.

aclose async
aclose() -> None

Close the HTTP connection pool.

delete async
delete(
    connector_id: str,
    key_field: str,
    key_value: str | int,
    object_name: str | None = None,
) -> Any

Delete one record through an UpdateConnector.

Parameters:

  • connector_id (str) –

    The UpdateConnector id.

  • key_field (str) –

    The key field, with or without the leading @.

  • key_value (str | int) –

    The key value of the record to delete.

  • object_name (str | None, default: None ) –

    The element to delete from; defaults to the connector itself.

Returns:

  • Any –

    Whatever AFAS returns, often nothing.

describe_get_connector async
describe_get_connector(connector_id: str) -> dict[str, Any]

Return the field definitions of a GetConnector.

Parameters:

  • connector_id (str) –

    The GetConnector id.

Returns:

  • dict[str, Any] –

    The metainfo document with name, description and fields.

describe_update_connector async
describe_update_connector(
    connector_id: str,
) -> dict[str, Any]

Return the schema of an UpdateConnector, including nested objects.

Parameters:

  • connector_id (str) –

    The UpdateConnector id.

Returns:

  • dict[str, Any] –

    The metainfo document with fields and objects.

fetch_rows async
fetch_rows(
    connector_id: str,
    *,
    skip: int = 0,
    take: int | None = None,
    filters: list[Filter] | None = None,
    order_by: list[str] | None = None,
) -> list[dict[str, Any]]

Return one page of rows from a GetConnector.

Parameters:

  • connector_id (str) –

    The GetConnector id.

  • skip (int, default: 0 ) –

    Number of rows to skip.

  • take (int | None, default: None ) –

    Number of rows to return; defaults to the configured page size.

  • filters (list[Filter] | None, default: None ) –

    Conditions to apply.

  • order_by (list[str] | None, default: None ) –

    Sort order; prefix a field with - for descending.

Returns:

  • list[dict[str, Any]] –

    The rows of the page, each a mapping of field id to value.

insert async
insert(
    connector_id: str,
    element: dict[str, Any] | list[dict[str, Any]],
) -> Any

Create records through an UpdateConnector.

Parameters:

Returns:

  • Any –

    Whatever AFAS returns, usually the keys of the created records.

list_connectors async
list_connectors() -> dict[str, Any]

Return the GetConnectors and UpdateConnectors the token may use, as AFAS reports them.

profit_version async
profit_version() -> dict[str, Any]

Return the Profit version information, which doubles as a connectivity and token check.

request async
request(
    method: str,
    path: str,
    *,
    params: dict[str, str] | None = None,
    body: dict[str, Any] | None = None,
) -> Any

Send one request to AFAS and return its decoded JSON body.

Parameters:

  • method (str) –

    HTTP method.

  • path (str) –

    Path relative to the REST services base URL.

  • params (dict[str, str] | None, default: None ) –

    Query parameters.

  • body (dict[str, Any] | None, default: None ) –

    JSON body for POST and PUT.

Returns:

  • Any –

    The decoded JSON response, or None when AFAS sent no body.

Raises:

  • AfasApiError –

    When AFAS answers with an HTTP error status.

update async
update(
    connector_id: str,
    element: dict[str, Any] | list[dict[str, Any]],
) -> Any

Change existing records through an UpdateConnector.

Parameters:

  • connector_id (str) –

    The UpdateConnector id.

  • element (dict[str, Any] | list[dict[str, Any]]) –

    The Element payload, including the @Key entries that identify the records.

Returns:

  • Any –

    Whatever AFAS returns, often nothing.

AfasError

Bases: Exception


              flowchart TD
              afas_mcp_server.client.AfasError[AfasError]

              

              click afas_mcp_server.client.AfasError href "" "afas_mcp_server.client.AfasError"
            

Base class for errors raised by the AFAS client.

connector_path
connector_path(*segments: str) -> str

Join path segments under connectors/, percent-encoding everything but @.

Parameters:

  • segments (str, default: () ) –

    The path segments after connectors.

Returns:

  • str –

    The relative request path.

decode_profit_error_header
decode_profit_error_header(value: str) -> dict[str, Any]

Decode the base64 X-PROFIT-ERROR header AFAS adds to failed calls.

Parameters:

  • value (str) –

    The raw header value.

Returns:

  • dict[str, Any] –

    The decoded JSON object, or the decoded text under profitError when it is not JSON.

error_details
error_details(response: Response) -> dict[str, Any]

Collect everything AFAS tells us about a failed call.

Parameters:

  • response (Response) –

    The error response.

Returns:

  • dict[str, Any] –

    The X-PROFIT-ERROR header and JSON body merged, or the plain text body under message.

parse_json
parse_json(response: Response) -> Any

Return the JSON body of a response, or None when there is none.

Parameters:

  • response (Response) –

    The HTTP response.

Returns:

  • Any –

    The decoded JSON value, or None for an empty or non-JSON body.

update_body
update_body(
    connector_id: str,
    element: dict[str, Any] | list[dict[str, Any]],
) -> dict[str, Any]

Wrap an element in the envelope UpdateConnectors expect.

Parameters:

  • connector_id (str) –

    The UpdateConnector id, e.g. KnSubject.

  • element (dict[str, Any] | list[dict[str, Any]]) –

    The Element payload with Fields and optional Objects.

Returns:

  • dict[str, Any] –

    The request body {connector_id: {"Element": element}}.

configuration

Runtime configuration for the AFAS MCP server, read from AFAS_* environment variables.

Classes:

  • Environment –

    The kind of AFAS Online environment, which selects the REST hostname.

  • Settings –

    Connection and behaviour settings, populated from AFAS_* environment variables or a .env file.

Functions:

  • encode_token –

    Return the base64 token AFAS expects after AfasToken in the Authorization header.

  • is_encoded_token –

    Return whether candidate is already the base64 form of a <token> XML document.

Environment

Bases: str, Enum


              flowchart TD
              afas_mcp_server.configuration.Environment[Environment]

              

              click afas_mcp_server.configuration.Environment href "" "afas_mcp_server.configuration.Environment"
            

The kind of AFAS Online environment, which selects the REST hostname.

Attributes:

  • host_prefix (str) –

    The hostname fragment AFAS Online uses for this environment kind.

host_prefix property
host_prefix: str

The hostname fragment AFAS Online uses for this environment kind.

Settings

Bases: BaseSettings


              flowchart TD
              afas_mcp_server.configuration.Settings[Settings]

              

              click afas_mcp_server.configuration.Settings href "" "afas_mcp_server.configuration.Settings"
            

Connection and behaviour settings, populated from AFAS_* environment variables or a .env file.

Either member_id (optionally with environment) or an explicit base_url must be provided.

Methods:

  • check_consistency –

    Reject settings that cannot produce a base URL or a usable log level.

Attributes:

authorization_header property
authorization_header: str

The value of the Authorization header sent with every AFAS call.

python_log_level property
python_log_level: str

The log level as Python's logging module spells it.

rest_base_url property
rest_base_url: str

The REST services base URL, without a trailing slash.

check_consistency
check_consistency() -> Self

Reject settings that cannot produce a base URL or a usable log level.

Returns:

  • Self –

    The validated settings, unchanged.

Raises:

  • ValueError –

    When neither an endpoint nor a known log level is available.

encode_token
encode_token(token: str) -> str

Return the base64 token AFAS expects after AfasToken in the Authorization header.

Accepts the token in any of the forms AFAS hands out: the full <token> XML, only the value of its <data> element, or the XML already base64 encoded.

Parameters:

  • token (str) –

    The app connector token in one of the accepted forms.

Returns:

  • str –

    The base64 encoded <token> XML.

is_encoded_token
is_encoded_token(candidate: str) -> bool

Return whether candidate is already the base64 form of a <token> XML document.

Parameters:

  • candidate (str) –

    The text to inspect.

Returns:

  • bool –

    True when the text base64-decodes to something that starts with <token.

filters

Filter, sort and paging expressions for GetConnector calls, rendered the way the AFAS REST API expects them.

Classes:

  • Filter –

    One condition on a GetConnector column.

  • Operator –

    Comparison operators AFAS supports in GetConnector filters, by readable name.

Functions:

  • compact_filter_params –

    Render filters as the filterfieldids/filtervalues/operatortypes query parameters.

  • filter_groups –

    Bucket filters by group number, in ascending group order.

  • filter_params –

    Render filters as query parameters, picking the compact syntax unless a separator forces JSON.

  • json_filter_params –

    Render filters as the filterjson query parameter.

  • needs_json_filter –

    Return whether any field or value contains a separator, which the compact syntax cannot escape.

  • order_by_param –

    Render the sort order as the orderbyfieldids query parameter.

  • query_params –

    Build the complete query string for a GetConnector call.

Filter

Bases: BaseModel


              flowchart TD
              afas_mcp_server.filters.Filter[Filter]

              

              click afas_mcp_server.filters.Filter href "" "afas_mcp_server.filters.Filter"
            

One condition on a GetConnector column.

Attributes:

  • rendered_value (str) –

    The value as text, with the wildcards AFAS expects for the text operators.

rendered_value property
rendered_value: str

The value as text, with the wildcards AFAS expects for the text operators.

Operator

Bases: str, Enum


              flowchart TD
              afas_mcp_server.filters.Operator[Operator]

              

              click afas_mcp_server.filters.Operator href "" "afas_mcp_server.filters.Operator"
            

Comparison operators AFAS supports in GetConnector filters, by readable name.

Attributes:

  • code (int) –

    The numeric operatortypes value AFAS uses for this operator.

code property
code: int

The numeric operatortypes value AFAS uses for this operator.

compact_filter_params
compact_filter_params(
    groups: list[list[Filter]],
) -> dict[str, str]

Render filters as the filterfieldids/filtervalues/operatortypes query parameters.

Parameters:

Returns:

  • dict[str, str] –

    The three query parameters, with , between AND conditions and ; between OR groups.

filter_groups
filter_groups(filters: list[Filter]) -> list[list[Filter]]

Bucket filters by group number, in ascending group order.

Parameters:

Returns:

  • list[list[Filter]] –

    One list per group; filters within a list are ANDed, lists are ORed.

filter_params
filter_params(
    filters: list[Filter] | None,
) -> dict[str, str]

Render filters as query parameters, picking the compact syntax unless a separator forces JSON.

Parameters:

  • filters (list[Filter] | None) –

    The conditions to render, or None for no filtering.

Returns:

  • dict[str, str] –

    Query parameters to add to the GetConnector request.

json_filter_params
json_filter_params(
    groups: list[list[Filter]],
) -> dict[str, str]

Render filters as the filterjson query parameter.

Parameters:

Returns:

  • dict[str, str] –

    A single filterjson parameter with one Filter entry per OR group.

needs_json_filter
needs_json_filter(filters: list[Filter]) -> bool

Return whether any field or value contains a separator, which the compact syntax cannot escape.

Parameters:

Returns:

  • bool –

    True when the JSON filter syntax must be used.

order_by_param
order_by_param(
    order_by: list[str] | None,
) -> dict[str, str]

Render the sort order as the orderbyfieldids query parameter.

Parameters:

  • order_by (list[str] | None) –

    Field ids to sort on; prefix with - for descending.

Returns:

  • dict[str, str] –

    The query parameter, or nothing when no sort order was given.

query_params
query_params(
    *,
    skip: int,
    take: int,
    filters: list[Filter] | None = None,
    order_by: list[str] | None = None,
) -> dict[str, str]

Build the complete query string for a GetConnector call.

Parameters:

  • skip (int) –

    Number of rows to skip.

  • take (int) –

    Number of rows to return.

  • filters (list[Filter] | None, default: None ) –

    Conditions to apply, if any.

  • order_by (list[str] | None, default: None ) –

    Sort order, if any.

Returns:

  • dict[str, str] –

    All query parameters for the request.

server

The MCP server: tools that expose the connectors of one AFAS Profit environment to an AI agent.

Classes:

  • AppContext –

    What every tool needs at request time.

Functions:

  • app_context –

    Return the shared settings and client that the lifespan created for this server.

  • build_server –

    Create the MCP server for one AFAS environment.

  • call_afas –

    Await an AFAS call, translating its errors into tool errors the model can read.

  • check_page –

    Reject paging parameters AFAS or the configured limits would not accept.

  • connection_info –

    Show which AFAS environment this server talks to and confirm the token works by asking for the Profit version.

  • delete –

    Permanently delete one record in AFAS through an UpdateConnector (HTTP DELETE).

  • describe_failure –

    Turn an AFAS error into a message the model can act on, including the internal detail when present.

  • describe_get_connector –

    Describe a GetConnector: its field ids, labels, data types and lengths. Use the ids in filters and order_by.

  • describe_update_connector –

    Describe an UpdateConnector: its fields (mandatory, key, allowed values) and the nested objects it accepts.

  • ensure_valid –

    Fetch the connector schema and refuse the payload when it has problems.

  • get_rows –

    Read one page of rows from a GetConnector, with optional filters and sort order.

  • insert –

    Create records in AFAS through an UpdateConnector (HTTP POST).

  • instructions_for –

    Compose the guidance the MCP client shows its model, depending on whether writes are enabled.

  • list_connectors –

    List the GetConnectors and UpdateConnectors the configured token may use, optionally filtered by keyword.

  • matching –

    Keep the connectors whose id or description contains the search text, case-insensitively.

  • package_version –

    Return the installed version of this package, or 0.0.0 when it is not installed.

  • register_read_tools –

    Register the tools that never change data in AFAS.

  • register_write_tools –

    Register the tools that create, change or delete data in AFAS.

  • update –

    Change existing records in AFAS through an UpdateConnector (HTTP PUT); identify them with "@KeyField" entries.

  • validate_payload –

    Check an UpdateConnector payload against the connector schema without sending it, and show the exact body.

AppContext dataclass
AppContext(settings: Settings, client: AfasClient)

What every tool needs at request time.

app_context
app_context(ctx: ToolContext) -> AppContext

Return the shared settings and client that the lifespan created for this server.

build_server
build_server(
    settings: Settings | None = None,
    transport: AsyncBaseTransport | None = None,
) -> MCPServer

Create the MCP server for one AFAS environment.

Parameters:

  • settings (Settings | None, default: None ) –

    Connection settings; read from the environment when omitted.

  • transport (AsyncBaseTransport | None, default: None ) –

    Optional HTTP transport for the AFAS client, used by tests to fake AFAS.

Returns:

  • MCPServer –

    A server with the read tools, and the write tools when the settings allow writes.

call_afas async
call_afas(operation: Awaitable[T]) -> T

Await an AFAS call, translating its errors into tool errors the model can read.

Parameters:

  • operation (Awaitable[T]) –

    The pending client call.

Returns:

  • T –

    The result of the call.

Raises:

  • ToolError –

    When AFAS rejected the call.

check_page
check_page(
    skip: int, take: int, settings: Settings
) -> None

Reject paging parameters AFAS or the configured limits would not accept.

Raises:

  • ToolError –

    When skip is negative or take is outside 1..max_take.

connection_info async
connection_info(ctx: ToolContext) -> dict[str, Any]

Show which AFAS environment this server talks to and confirm the token works by asking for the Profit version.

delete async
delete(
    ctx: ToolContext,
    connector_id: UpdateConnectorId,
    key_field: Annotated[
        str,
        Field(
            description='Primary key field id of the record, e.g. SbId.'
        ),
    ],
    key_value: Annotated[
        str | int,
        Field(
            description='Value of the key field for the record to delete.'
        ),
    ],
    *,
    object_name: Annotated[
        str | None,
        Field(
            description='Nested object to delete from; defaults to the connector itself.'
        ),
    ] = None,
) -> dict[str, Any]

Permanently delete one record in AFAS through an UpdateConnector (HTTP DELETE).

describe_failure
describe_failure(error: AfasApiError) -> str

Turn an AFAS error into a message the model can act on, including the internal detail when present.

describe_get_connector async
describe_get_connector(
    ctx: ToolContext, connector_id: ConnectorId
) -> dict[str, Any]

Describe a GetConnector: its field ids, labels, data types and lengths. Use the ids in filters and order_by.

describe_update_connector async
describe_update_connector(
    ctx: ToolContext, connector_id: UpdateConnectorId
) -> dict[str, Any]

Describe an UpdateConnector: its fields (mandatory, key, allowed values) and the nested objects it accepts.

ensure_valid async
ensure_valid(
    client: AfasClient,
    connector_id: str,
    element: Element,
    operation: Operation,
) -> None

Fetch the connector schema and refuse the payload when it has problems.

Raises:

  • ToolError –

    Listing every problem found, so the model can fix them all at once.

get_rows async
get_rows(
    ctx: ToolContext,
    connector_id: ConnectorId,
    *,
    skip: Annotated[
        int,
        Field(
            description='Number of rows to skip; combine with take to page.'
        ),
    ] = 0,
    take: Annotated[
        int | None,
        Field(
            description='Rows to return; defaults to the configured page size.'
        ),
    ] = None,
    filters: Annotated[
        list[Filter] | None,
        Field(
            description='Conditions on field ids. Same group = AND, different groups = OR.'
        ),
    ] = None,
    order_by: Annotated[
        list[str] | None,
        Field(
            description='Field ids to sort on, prefix with - for descending. Required for reliable paging.'
        ),
    ] = None,
) -> dict[str, Any]

Read one page of rows from a GetConnector, with optional filters and sort order.

insert async
insert(
    ctx: ToolContext,
    connector_id: UpdateConnectorId,
    element: ElementPayload,
    *,
    validate: Annotated[
        bool,
        Field(
            description='Check the payload against the schema before sending.'
        ),
    ] = True,
) -> dict[str, Any]

Create records in AFAS through an UpdateConnector (HTTP POST).

instructions_for
instructions_for(settings: Settings) -> str

Compose the guidance the MCP client shows its model, depending on whether writes are enabled.

list_connectors async
list_connectors(
    ctx: ToolContext,
    *,
    kind: Annotated[
        ConnectorKind,
        Field(
            description='Which connectors to list: get (read), update (write) or all.'
        ),
    ] = 'all',
    search: Annotated[
        str | None,
        Field(
            description='Keep only connectors whose id or description contains this.'
        ),
    ] = None,
) -> dict[str, Any]

List the GetConnectors and UpdateConnectors the configured token may use, optionally filtered by keyword.

matching
matching(
    items: list[dict[str, Any]], search: str | None
) -> list[dict[str, Any]]

Keep the connectors whose id or description contains the search text, case-insensitively.

package_version
package_version() -> str

Return the installed version of this package, or 0.0.0 when it is not installed.

register_read_tools
register_read_tools(server: MCPServer) -> None

Register the tools that never change data in AFAS.

register_write_tools
register_write_tools(server: MCPServer) -> None

Register the tools that create, change or delete data in AFAS.

update async
update(
    ctx: ToolContext,
    connector_id: UpdateConnectorId,
    element: ElementPayload,
    *,
    validate: Annotated[
        bool,
        Field(
            description='Check the payload against the schema before sending.'
        ),
    ] = True,
) -> dict[str, Any]

Change existing records in AFAS through an UpdateConnector (HTTP PUT); identify them with "@KeyField" entries.

validate_payload async
validate_payload(
    ctx: ToolContext,
    connector_id: UpdateConnectorId,
    element: ElementPayload,
    *,
    operation: Annotated[
        Operation,
        Field(
            description='insert requires all mandatory fields; update does not.'
        ),
    ] = 'insert',
) -> dict[str, Any]

Check an UpdateConnector payload against the connector schema without sending it, and show the exact body.

validation

Offline checks of UpdateConnector payloads against the schema AFAS publishes for the connector.

Classes:

  • Issue –

    One problem found in a payload.

Functions:

  • element_issues –

    Yield every problem in an Element payload, recursing into nested objects.

  • field_value_issues –

    Yield problems with one field value: type, length and allowed values.

  • fields_by_id –

    Index the fields of a schema node by field id.

  • fields_issues –

    Yield problems with the Fields mapping of a record.

  • is_integer –

    Return whether value is an int and not a bool.

  • is_number –

    Return whether value is an int or float and not a bool.

  • join_path –

    Join non-empty path parts with dots.

  • key_issues –

    Yield problems with the @Key entries that identify a record.

  • mandatory_issues –

    Yield the mandatory fields an insert leaves out.

  • object_issues –

    Yield problems inside one nested object: unknown name, missing Element, or issues in that element.

  • objects_by_name –

    Index the nested objects of a schema node by name.

  • objects_issues –

    Yield problems inside Objects, which AFAS accepts as a mapping or as a list of single-key mappings.

  • unknown_key_issues –

    Yield element keys that are neither @Key entries nor Fields/Objects.

  • validate_element –

    Check an Element payload against an UpdateConnector schema without calling AFAS.

Issue

Bases: BaseModel


              flowchart TD
              afas_mcp_server.validation.Issue[Issue]

              

              click afas_mcp_server.validation.Issue href "" "afas_mcp_server.validation.Issue"
            

One problem found in a payload.

element_issues
element_issues(
    schema: dict[str, Any],
    element: object,
    operation: str,
    path: str = '',
) -> Iterator[Issue]

Yield every problem in an Element payload, recursing into nested objects.

Parameters:

  • schema (dict[str, Any]) –

    The connector or nested object schema from metainfo.

  • element (object) –

    The Element value; anything but a mapping or a list of mappings is itself reported.

  • operation (str) –

    insert or update; only inserts must supply all mandatory fields.

  • path (str, default: '' ) –

    Where the element sits in the payload.

field_value_issues
field_value_issues(
    field: dict[str, Any], value: object, path: str
) -> Iterator[Issue]

Yield problems with one field value: type, length and allowed values.

Parameters:

  • field (dict[str, Any]) –

    The field definition from the schema.

  • value (object) –

    The supplied value.

  • path (str) –

    Where the value sits in the payload.

fields_by_id
fields_by_id(
    schema: dict[str, Any],
) -> dict[str, dict[str, Any]]

Index the fields of a schema node by field id.

fields_issues
fields_issues(
    element: dict[str, Any],
    fields: dict[str, dict[str, Any]],
    path: str,
) -> Iterator[Issue]

Yield problems with the Fields mapping of a record.

is_integer
is_integer(value: object) -> bool

Return whether value is an int and not a bool.

is_number
is_number(value: object) -> bool

Return whether value is an int or float and not a bool.

join_path
join_path(*parts: str) -> str

Join non-empty path parts with dots.

key_issues
key_issues(
    element: dict[str, Any],
    fields: dict[str, dict[str, Any]],
    path: str,
) -> Iterator[Issue]

Yield problems with the @Key entries that identify a record.

mandatory_issues
mandatory_issues(
    element: dict[str, Any],
    fields: dict[str, dict[str, Any]],
    path: str,
) -> Iterator[Issue]

Yield the mandatory fields an insert leaves out.

object_issues
object_issues(
    name: str,
    node: object,
    objects: dict[str, dict[str, Any]],
    operation: str,
    object_path: str,
) -> Iterator[Issue]

Yield problems inside one nested object: unknown name, missing Element, or issues in that element.

objects_by_name
objects_by_name(
    schema: dict[str, Any],
) -> dict[str, dict[str, Any]]

Index the nested objects of a schema node by name.

objects_issues
objects_issues(
    element: dict[str, Any],
    objects: dict[str, dict[str, Any]],
    operation: str,
    path: str,
) -> Iterator[Issue]

Yield problems inside Objects, which AFAS accepts as a mapping or as a list of single-key mappings.

unknown_key_issues
unknown_key_issues(
    element: dict[str, Any], path: str
) -> Iterator[Issue]

Yield element keys that are neither @Key entries nor Fields/Objects.

validate_element
validate_element(
    schema: dict[str, Any], element: object, operation: str
) -> list[Issue]

Check an Element payload against an UpdateConnector schema without calling AFAS.

Parameters:

  • schema (dict[str, Any]) –

    The UpdateConnector schema as returned by metainfo/update/{id}.

  • element (object) –

    The Element payload that would be sent; a mapping or a list of mappings.

  • operation (str) –

    insert or update.

Returns:

  • list[Issue] –

    The problems found; empty when the payload looks valid.