Safefood 360 MCP by usefulapi

Read Safefood 360 documents, complaints, suppliers, materials; create complaints, update documents.

Should I use this

Quality & Safety

A
Description quality
95%
Schema completeness
97%
Naming quality
76%
Poisoning risk
100%
Permission match
100%
Protocol compliance
100%

Findings (3)

  • LOWTool 'safefood360_list_document_reviews' name length outside 3-30 rangein safefood360_list_document_reviews
  • LOWTool 'safefood360_get_document_review' name length outside 3-30 rangein safefood360_get_document_review
  • LOWTool 'safefood360_get_batching_record' name length outside 3-30 rangein safefood360_get_batching_record

Based on automated analysis of tool definitions and protocol compliance.

Context Cost

~3,687Tokens (tool definitions)
~1.5 KBTypical response size
Significant attention impact (2.88% of 128k context)

This is the approximate number of tokens consumed each time the server's tools are loaded into a model's context. Higher counts reduce the attention available for other tasks.

Install

One-Click Install

Add this to your `claude_desktop_config.json` file:

{
  "mcpServers": {
    "safefood-360": {
      "url": "https://safefood-360.usefulapi.io/mcp"
    }
  }
}

Remote endpoints

https://safefood-360.usefulapi.io/mcpstreamable-http

What it can do

Tool inventory

Tools (17)

🟢 Read-only🟡 Write🔴 Delete⚪ Unknown
🟢safefood360_list_documents(filter, orderby, top, skip, count)

List controlled documents of the Safefood 360 site (title, description, version, folder, responsible person, review/approval workflow, created/modified). Supports OData $filter, $orderby, $top, $skip and $count. GET /documents/sites/{siteId}/v1/documents/.

Input Schema

{
  "type": "object",
  "properties": {
    "filter": {
      "description": "OData $filter, e.g. \"date ge 2026-01-01T00:00:00Z\" (comparison, logical and string operators).",
      "type": "string",
      "maxLength": 1000
    },
    "orderby": {
      "description": "OData $orderby, e.g. \"date desc,name asc\".",
      "type": "string",
      "maxLength": 300
    },
    "top": {
      "description": "Records per page, 1-1000 (the vendor default is 100).",
      "type": "integer",
      "minimum": 1,
      "maximum": 1000
    },
    "skip": {
      "description": "Records to skip (offset). Pass the previous reply's next_skip.",
      "type": "integer",
      "minimum": 0,
      "maximum": 1000000
    },
    "count": {
      "description": "Include the total count of matching records in the reply.",
      "type": "boolean"
    }
  },
  "$schema": "https://json-schema.org/draft/2020-12/schema"
}
🟢safefood360_get_document(identifier)

One controlled document by its identifier: title, description, version, folder, responsible person and workflow. GET /documents/sites/{siteId}/v1/documents/{identifier}.

Input Schema

{
  "type": "object",
  "properties": {
    "identifier": {
      "type": "string",
      "minLength": 1,
      "maxLength": 200,
      "description": "Document identifier (as shown in Safefood 360)."
    }
  },
  "required": [
    "identifier"
  ],
  "$schema": "https://json-schema.org/draft/2020-12/schema"
}
🟢safefood360_list_document_reviews(filter, orderby, top, skip, count)

List document reviews (the periodic review records of controlled documents). Supports OData $filter, $orderby, $top, $skip and $count; use it to find reviews that are due or overdue. GET /documents/sites/{siteId}/v1/documentreviews/.

Input Schema

{
  "type": "object",
  "properties": {
    "filter": {
      "description": "OData $filter, e.g. \"date ge 2026-01-01T00:00:00Z\" (comparison, logical and string operators).",
      "type": "string",
      "maxLength": 1000
    },
    "orderby": {
      "description": "OData $orderby, e.g. \"date desc,name asc\".",
      "type": "string",
      "maxLength": 300
    },
    "top": {
      "description": "Records per page, 1-1000 (the vendor default is 100).",
      "type": "integer",
      "minimum": 1,
      "maximum": 1000
    },
    "skip": {
      "description": "Records to skip (offset). Pass the previous reply's next_skip.",
      "type": "integer",
      "minimum": 0,
      "maximum": 1000000
    },
    "count": {
      "description": "Include the total count of matching records in the reply.",
      "type": "boolean"
    }
  },
  "$schema": "https://json-schema.org/draft/2020-12/schema"
}
🟢safefood360_get_document_review(review_no)

One document review by its review number. GET /documents/sites/{siteId}/v1/documentreviews/{no}.

Input Schema

{
  "type": "object",
  "properties": {
    "review_no": {
      "type": "string",
      "minLength": 1,
      "maxLength": 200,
      "description": "Document review number."
    }
  },
  "required": [
    "review_no"
  ],
  "$schema": "https://json-schema.org/draft/2020-12/schema"
}
🟢safefood360_list_complaints(filter, orderby, top, skip, count)

List customer complaints (number, name, risk, date, company, source, contact person, product/material, description, created/modified). Supports OData $filter, $orderby, $top, $skip and $count. GET /complaints/sites/{siteId}/v1/complaints.

Input Schema

{
  "type": "object",
  "properties": {
    "filter": {
      "description": "OData $filter, e.g. \"date ge 2026-01-01T00:00:00Z\" (comparison, logical and string operators).",
      "type": "string",
      "maxLength": 1000
    },
    "orderby": {
      "description": "OData $orderby, e.g. \"date desc,name asc\".",
      "type": "string",
      "maxLength": 300
    },
    "top": {
      "description": "Records per page, 1-1000 (the vendor default is 100).",
      "type": "integer",
      "minimum": 1,
      "maximum": 1000
    },
    "skip": {
      "description": "Records to skip (offset). Pass the previous reply's next_skip.",
      "type": "integer",
      "minimum": 0,
      "maximum": 1000000
    },
    "count": {
      "description": "Include the total count of matching records in the reply.",
      "type": "boolean"
    }
  },
  "$schema": "https://json-schema.org/draft/2020-12/schema"
}
🟢safefood360_get_complaint(complaint_id)

One complaint by its id (GUID). GET /complaints/sites/{siteId}/v1/complaints/{id}.

Input Schema

{
  "type": "object",
  "properties": {
    "complaint_id": {
      "type": "string",
      "pattern": "^[0-9a-fA-F-]{36}$",
      "description": "Complaint id (GUID), e.g. from safefood360_list_complaints."
    }
  },
  "required": [
    "complaint_id"
  ],
  "$schema": "https://json-schema.org/draft/2020-12/schema"
}
🟢safefood360_list_suppliers(start_index, limit, is_archived, sort, order)

List suppliers (name, code, addresses, contacts, approval status, risk, establishment numbers). Paged with start_index and limit; the reply carries recordCount and next_start_index. GET /v1/suppliers/?siteId=.

Input Schema

{
  "type": "object",
  "properties": {
    "start_index": {
      "description": "Index of the first record (default 0). Pass the previous reply's next_start_index.",
      "type": "integer",
      "minimum": 0,
      "maximum": 1000000
    },
    "limit": {
      "description": "Records per page, 1-100 (default 30).",
      "type": "integer",
      "minimum": 1,
      "maximum": 100
    },
    "is_archived": {
      "description": "true = archived records, false = active records (default: the vendor's default).",
      "type": "boolean"
    },
    "sort": {
      "description": "Field to sort by.",
      "type": "string",
      "maxLength": 100
    },
    "order": {
      "description": "Sort direction.",
      "type": "string",
      "enum": [
        "asc",
        "desc"
      ]
    }
  },
  "$schema": "https://json-schema.org/draft/2020-12/schema"
}
🟢safefood360_get_supplier(external_id)

One supplier by its external id. GET /v1/suppliers/{externalId}?siteId=.

Input Schema

{
  "type": "object",
  "properties": {
    "external_id": {
      "type": "string",
      "minLength": 1,
      "maxLength": 200,
      "description": "Supplier external id."
    }
  },
  "required": [
    "external_id"
  ],
  "$schema": "https://json-schema.org/draft/2020-12/schema"
}
🟢safefood360_list_materials(start_index, limit, is_archived, sort, order)

List materials/ingredients (name, our code, supplier code, description, category, countries of origin, risk, archived flag). Paged with start_index and limit; the reply carries recordCount and next_start_index. GET /v1/materials/?siteId=.

Input Schema

{
  "type": "object",
  "properties": {
    "start_index": {
      "description": "Index of the first record (default 0). Pass the previous reply's next_start_index.",
      "type": "integer",
      "minimum": 0,
      "maximum": 1000000
    },
    "limit": {
      "description": "Records per page, 1-100 (default 30).",
      "type": "integer",
      "minimum": 1,
      "maximum": 100
    },
    "is_archived": {
      "description": "true = archived records, false = active records (default: the vendor's default).",
      "type": "boolean"
    },
    "sort": {
      "description": "Field to sort by.",
      "type": "string",
      "maxLength": 100
    },
    "order": {
      "description": "Sort direction.",
      "type": "string",
      "enum": [
        "asc",
        "desc"
      ]
    }
  },
  "$schema": "https://json-schema.org/draft/2020-12/schema"
}
🟢safefood360_get_material(external_id)

One material by its external id. GET /v1/materials/{externalId}?siteId=.

Input Schema

{
  "type": "object",
  "properties": {
    "external_id": {
      "type": "string",
      "minLength": 1,
      "maxLength": 200,
      "description": "Material external id."
    }
  },
  "required": [
    "external_id"
  ],
  "$schema": "https://json-schema.org/draft/2020-12/schema"
}
🟢safefood360_get_customer(identifier)

One customer by its identifier (name, addresses, phone, notes). The vendor offers no customer list. GET /customers/sites/{siteId}/v1/customers/{identifier}.

Input Schema

{
  "type": "object",
  "properties": {
    "identifier": {
      "type": "string",
      "minLength": 1,
      "maxLength": 200,
      "description": "Customer identifier."
    }
  },
  "required": [
    "identifier"
  ],
  "$schema": "https://json-schema.org/draft/2020-12/schema"
}
🟢safefood360_get_employee(identifier)

One employee record by its identifier (training/HR master data of the site). Contains personal data: use it only for the question asked. The vendor offers no employee list. GET /employees/sites/{siteId}/v1/employees/{identifier}.

Input Schema

{
  "type": "object",
  "properties": {
    "identifier": {
      "type": "string",
      "minLength": 1,
      "maxLength": 200,
      "description": "Employee identifier."
    }
  },
  "required": [
    "identifier"
  ],
  "$schema": "https://json-schema.org/draft/2020-12/schema"
}
🟢safefood360_get_final_product(identifier)

One final (finished) product by its identifier: name, folder, categories, barcode, specifications and the materials it is made of. The vendor offers no final-product list. GET /finalproducts/sites/{siteId}/v1/finalproducts/{identifier}.

Input Schema

{
  "type": "object",
  "properties": {
    "identifier": {
      "type": "string",
      "minLength": 1,
      "maxLength": 200,
      "description": "Final product identifier."
    }
  },
  "required": [
    "identifier"
  ],
  "$schema": "https://json-schema.org/draft/2020-12/schema"
}
🟢safefood360_get_batching_record(record_id)

One batching (traceability) record by its id (GUID). GET /batching/sites/{siteId}/v1/batching/records/{recordId}.

Input Schema

{
  "type": "object",
  "properties": {
    "record_id": {
      "type": "string",
      "pattern": "^[0-9a-fA-F-]{36}$",
      "description": "Batching record id (GUID)."
    }
  },
  "required": [
    "record_id"
  ],
  "$schema": "https://json-schema.org/draft/2020-12/schema"
}
🔴safefood360_update_document(identifier, title, description, folder)

WRITE: change the title, description and/or folder of a controlled document in Safefood 360 (JSON patch; fields you leave out stay as they are). It does not publish a new version or change the review workflow. Returns the updated document. PATCH /documents/sites/{siteId}/v1/documents/{identifier}.

Input Schema

{
  "type": "object",
  "properties": {
    "identifier": {
      "type": "string",
      "minLength": 1,
      "maxLength": 200,
      "description": "Document identifier."
    },
    "title": {
      "description": "New title.",
      "type": "string",
      "minLength": 1,
      "maxLength": 500
    },
    "description": {
      "description": "New description.",
      "type": "string",
      "maxLength": 5000
    },
    "folder": {
      "description": "Folder to move the document to.",
      "type": "string",
      "minLength": 1,
      "maxLength": 500
    }
  },
  "required": [
    "identifier"
  ],
  "$schema": "https://json-schema.org/draft/2020-12/schema"
}
🔴safefood360_update_customer(identifier, name, phone, mobile, notes)

WRITE: change the name, phone, mobile and/or notes of a customer in Safefood 360 (JSON patch of those fields; others stay as they are). notes REPLACES the existing notes. PATCH /customers/sites/{siteId}/v1/customers/{identifier}.

Input Schema

{
  "type": "object",
  "properties": {
    "identifier": {
      "type": "string",
      "minLength": 1,
      "maxLength": 200,
      "description": "Customer identifier."
    },
    "name": {
      "description": "New customer name.",
      "type": "string",
      "minLength": 1,
      "maxLength": 300
    },
    "phone": {
      "description": "New phone number.",
      "type": "string",
      "maxLength": 60
    },
    "mobile": {
      "description": "New mobile number.",
      "type": "string",
      "maxLength": 60
    },
    "notes": {
      "description": "New notes (replaces the existing notes).",
      "type": "string",
      "maxLength": 5000
    }
  },
  "required": [
    "identifier"
  ],
  "$schema": "https://json-schema.org/draft/2020-12/schema"
}
🟡safefood360_create_complaint(description, date, risk, recorded_by, company_id, ...)

WRITE: record a NEW complaint in Safefood 360 (it may trigger the site's complaint workflow and notifications). Not idempotent: calling it twice creates two complaints. Safefood 360 validates the fields (ids such as source, company and recorded_by are GUIDs from your site's lists) and rejects a request that lacks required ones. POST /complaints/sites/{siteId}/v1/complaints/.

Input Schema

{
  "type": "object",
  "properties": {
    "description": {
      "type": "string",
      "minLength": 1,
      "maxLength": 5000,
      "description": "What the complaint is about."
    },
    "date": {
      "description": "When the complaint was received, ISO 8601, e.g. 2026-10-20T09:30:00Z.",
      "type": "string",
      "maxLength": 40
    },
    "risk": {
      "description": "Risk level as named in Safefood 360, e.g. None, Low, Medium, High.",
      "type": "string",
      "maxLength": 50
    },
    "recorded_by": {
      "type": "string",
      "pattern": "^[0-9a-fA-F-]{36}$",
      "description": "User id (GUID) of the person recording the complaint."
    },
    "company_id": {
      "type": "string",
      "pattern": "^[0-9a-fA-F-]{36}$",
      "description": "Customer/company id (GUID) the complaint is about."
    },
    "source": {
      "type": "string",
      "pattern": "^[0-9a-fA-F-]{36}$",
      "description": "Complaint source id (GUID) from the site's list of sources."
    },
    "source_details": {
      "description": "Free-text details of the source.",
      "type": "string",
      "maxLength": 1000
    },
    "reference": {
      "description": "The complainant's own reference.",
      "type": "string",
      "maxLength": 200
    },
    "sample_details": {
      "description": "Sample request and collection details.",
      "type": "string",
      "maxLength": 2000
    },
    "contact_person": {
      "description": "The complainant.",
      "type": "object",
      "properties": {
        "title": {
          "type": "string",
          "maxLength": 50
        },
        "first_name": {
          "type": "string",
          "maxLength": 100
        },
        "last_name": {
          "type": "string",
          "maxLength": 100
        },
        "address": {
          "type": "string",
          "maxLength": 500
        },
        "purchased": {
          "description": "Where the product was purchased.",
          "type": "string",
          "maxLength": 200
        },
        "phone": {
          "type": "string",
          "maxLength": 60
        },
        "mobile": {
          "type": "string",
          "maxLength": 60
        },
        "email": {
          "type": "string",
          "maxLength": 254
        }
      }
    },
    "product_id": {
      "type": "string",
      "pattern": "^[0-9a-fA-F-]{36}$",
      "description": "Id (GUID) of the product, material or service complained about."
    },
    "quantity": {
      "description": "Quantity affected.",
      "type": "integer",
      "minimum": 0,
      "maximum": 1000000
    },
    "trace_no": {
      "description": "Batch / trace number of the product.",
      "type": "string",
      "maxLength": 200
    }
  },
  "required": [
    "description"
  ],
  "$schema": "https://json-schema.org/draft/2020-12/schema"
}

Community

Rate this Server

Evidence

Recent observations

verifiedversion not recorded17 tools