Skip to main content
Glama
schubergphilis

AFAS MCP Server

AFAS MCP Server

Version Python License Documentation: Diátaxis Build Coverage pyscn quality

An open-source Model Context Protocol server for AFAS Profit. It lets AI assistants such as Claude Desktop, Claude Code, Cursor or any other MCP client read data through your GetConnectors, inspect connector schemas, and, only when you switch it on, write through UpdateConnectors.

  • Read-only by default. Insert, update and delete tools exist only when AFAS_ALLOW_WRITES=true.

  • Your connectors, your rules. The server sees exactly the GetConnectors and UpdateConnectors that the AFAS app connector behind the token allows. Nothing is bundled or hard-coded.

  • Schema-aware. Field definitions come from AFAS metainfo, and write payloads are validated against the UpdateConnector schema before anything is sent.

  • Readable filters. Filters are expressed by field id and operator name (contains, greater_than, ...) and rendered into the AFAS query syntax, including OR groups and the JSON filter fallback.

  • Runs anywhere an MCP client does. stdio for desktop clients, streamable HTTP for shared deployments.

How it fits together

flowchart LR
    client["<b>MCP client</b><br/>Claude Desktop · Claude Code · Cursor · ..."]

    subgraph server["afas-mcp-server &nbsp;·&nbsp; one AFAS token &nbsp;·&nbsp; read-only by default"]
        direction TB
        read["<b>Read tools</b> (always on)<br/>afas_connection_info · afas_list_connectors<br/>afas_describe_get_connector · afas_describe_update_connector<br/>afas_get_rows · afas_validate_payload"]
        filters["Filters by field id and operator name,<br/>rendered to the AFAS query syntax"]
        write["<b>Write tools</b> (only with AFAS_ALLOW_WRITES=true)<br/>afas_insert · afas_update · afas_delete"]
        validate["Offline validation against<br/>the UpdateConnector schema"]
        read --> filters
        write --> validate
    end

    subgraph afas["AFAS Profit REST services"]
        direction TB
        meta["metainfo"]
        get["GetConnectors"]
        upd["UpdateConnectors"]
    end

    client <-- "MCP over stdio<br/>or streamable HTTP" --> server
    read -- "GET" --> meta
    filters -- "GET · skip, take, orderby" --> get
    validate -- "POST · PUT · DELETE" --> upd

    classDef writes fill:#fff4e5,stroke:#e08a00,color:#5c3d00
    class write,validate writes

The assistant discovers connectors and fields through AFAS metainfo, reads rows through GetConnectors with filters and paging, and can only reach UpdateConnectors when the operator has enabled writes, and then only after the payload has been checked against the connector's schema.

Related MCP server: Salesforce MCP Server

Quick start

  1. In AFAS Profit, create an app connector (Algemeen > Beheer > App connector), add the GetConnectors and UpdateConnectors the assistant may use, and create a token for a user. Note the environment number from your AFAS Online URL, e.g. 12345 in https://12345.afasonline.com.

  2. Install uv and verify the connection:

    export AFAS_MEMBER_ID=12345
    export AFAS_TOKEN='<token><version>1</version><data>YOUR_TOKEN_DATA</data></token>'
    uvx afas-mcp-server --check

    You should see the base URL the server will talk to and the Profit version AFAS reports.

  3. Register the server with your MCP client. For Claude Desktop, add this to claude_desktop_config.json:

    {
      "mcpServers": {
        "afas": {
          "command": "uvx",
          "args": ["afas-mcp-server"],
          "env": {
            "AFAS_MEMBER_ID": "12345",
            "AFAS_TOKEN": "<token><version>1</version><data>YOUR_TOKEN_DATA</data></token>"
          }
        }
      }
    }

    For Claude Code:

    claude mcp add afas -e AFAS_MEMBER_ID=12345 -e AFAS_TOKEN='<token>...</token>' -- uvx afas-mcp-server
  4. Ask your assistant something like "Which AFAS connectors can you use?" or "Show the ten most recently changed employees." It will discover connectors, read their field definitions and page through rows.

Until the package is published on PyPI, run it from a checkout instead: uv run afas-mcp-server, or from git with uvx --from git+https://github.com/schubergphilis/afas_mcp_server afas-mcp-server.

Tools

Tool

Changes data

Purpose

afas_connection_info

no

Which environment the server talks to; proves the token works.

afas_list_connectors

no

GetConnectors and UpdateConnectors available to the token, with keyword search.

afas_describe_get_connector

no

Field ids, labels, types and lengths of a GetConnector.

afas_describe_update_connector

no

Fields, mandatory flags, allowed values and nested objects of an UpdateConnector.

afas_get_rows

no

One page of rows with filters, sort order and paging metadata.

afas_validate_payload

no

Check an UpdateConnector payload against its schema and show the body that would be sent.

afas_insert

yes

Create records (HTTP POST). Only with AFAS_ALLOW_WRITES=true.

afas_update

yes

Change records (HTTP PUT). Only with AFAS_ALLOW_WRITES=true.

afas_delete

yes

Delete one record (HTTP DELETE). Only with AFAS_ALLOW_WRITES=true.

The full parameter reference is in docs/reference/tools.md.

Configuration

Settings come from AFAS_* environment variables or a .env file in the working directory (see .env.example).

Variable

Default

Effect

AFAS_TOKEN

required

App connector token: the <token> XML, only its <data> value, or the base64 form.

AFAS_MEMBER_ID

AFAS Online environment number. Required unless AFAS_BASE_URL is set.

AFAS_ENVIRONMENT

production

production, test or accept; selects rest, resttest or restaccept.

AFAS_BASE_URL

Full REST base URL; overrides member id and environment.

AFAS_ALLOW_WRITES

false

Register the insert, update and delete tools.

AFAS_DEFAULT_TAKE

100

Rows per page when a call gives no take.

AFAS_MAX_TAKE

1000

Largest take a call may request.

AFAS_TIMEOUT_SECONDS

60

HTTP timeout per AFAS call.

AFAS_LANGUAGE

nl-nl

Language of AFAS messages: nl-nl, nl-be, fr-fr, de-de or en-us.

AFAS_LOG_LEVEL

INFO

Log level; logs go to stderr so stdio stays clean.

Command line: afas-mcp-server [--transport stdio|streamable-http] [--host H] [--port P] [--path /mcp] [--check].

Writing to AFAS

Writes are off until you set AFAS_ALLOW_WRITES=true. With writes on, the assistant is instructed to describe the UpdateConnector, validate the payload and show the change before sending it, and every write tool validates the payload against the schema first (switch off per call with validate: false). Recommended practice:

  • Start against your AFAS test environment (AFAS_ENVIRONMENT=test).

  • Give the token an app connector with only the connectors the assistant needs.

  • Keep separate tokens, and separate server instances, for read-only and writing use.

Security notes

  • The token is a credential for your ERP and HR data. Keep it in environment variables or a .env file that is not committed; never paste it into a prompt.

  • The server forwards calls to AFAS and nothing else. It stores no data and calls no other service.

  • The streamable HTTP transport has no authentication of its own. Bind it to localhost or put it behind a reverse proxy that authenticates clients.

How this repository is maintained

An AI agent, running as the Claude Code GitHub Action, maintains this repository under human supervision. Its standing instructions are in AGENTS.md: what it must never do (make writing possible by default, touch credentials, add a non-permissive dependency, push to main, publish), how it runs the checks, and the weekly checklist it works through.

  • Dependencies. Dependabot proposes updates every Monday after a seven-day release cooldown. A workflow merges GitHub Actions and non-major tooling updates once CI is green; the agent reviews runtime dependencies and major bumps, fixes the code when an update breaks it, and approves or asks a human.

  • Health. Every week the agent checks failing builds, security audit findings, expiring audit overrides, untriaged issues and a stale lockfile, opens pull requests for what it can fix, and posts a summary on the Maintenance log issue.

  • Requests. Maintainers ask for changes with @claude in any issue or pull request. Text from people without write access is treated as data, never as instructions.

  • Humans decide releases, publishing, anything verified against a real AFAS environment, license questions and security disclosures.

Contributors follow the same rules; see CONTRIBUTING.md. The wiring and the repository settings it relies on are described in Maintain the repository with an agent.

Documentation

Full documentation lives in docs/: build and open it with ./workflow.cmd document, or read it online at https://schubergphilis.github.io/afas_mcp_server/ once GitHub Pages is enabled for the repository.

Developing

Development flow as Paleofuturistic Python

Prerequisite: uv. Every development action runs through ./workflow.cmd <task>: the first run bootstraps the environment automatically. ./workflow.cmd lint and ./workflow.cmd test are the two you will use most.

The scaffold manual lives in the docs' Developer section: start with First-run setup; the full command list is in the Invoke task catalog.

License

Apache-2.0. AFAS and AFAS Profit are trademarks of AFAS Software B.V.; this project is not affiliated with AFAS.

Related MCP Connectors

Related MCP Servers

  • F
    license
    C
    quality
    Not graded
    maintenance
    Enables AI assistants to securely access and interact with Simplicate business data including CRM, projects, timesheets, and invoices through natural language. Supports searching across resources and retrieving detailed information about organizations, contacts, and project data.
    59
    0
    -
  • F
    license
    A
    quality
    D
    maintenance
    Enables AI assistants to interact with Salesforce data by listing objects, describing fields, and executing SOQL queries.
    4
    -
  • A
    license
    A
    quality
    B
    maintenance
    Lets AI assistants safely explore a Matrix42 instance by discovering web services and the data model, running validated ASQL queries, searching the service desk, and previewing ticket actions — read-only by default and without exposing credentials.
    5
    31 npm
    MIT