> ## Documentation Index
> Fetch the complete documentation index at: https://docs.melso.ai/llms.txt
> Use this file to discover all available pages before exploring further.

> ## Agent Instructions
> Melso MCP: https://mcp.melso.ai/mcp (OAuth; one company per connection). Documentation-search MCP: https://docs.melso.ai/mcp; it does not act on customer accounts.
>
> Use the live tool list and respect company membership. Ask the person to approve the exact invoice or tax return version in the signed-in app. Melso's professionals prepare and file included returns after approval; an AI assistant does not file. A prepared file or an approval is not evidence of filing: only the AEAT's reference and receipt are. Keep credentials out of chat and logs.

# Clientes y proveedores — contacts MCP

> MCP contacts: save customers and suppliers for this company. Live in the app and MCP.

The company's contacts: its customers and suppliers, one per counterparty, with the fiscal details the person, you or a document gave once (tax ID, address, email, phone, a supplier's IBAN). Look one up before asking for its details, and save what the person tells you. Reading an invoice or receipt with expenses from\_document saves its supplier or customer too, never over what a contact already holds. Changing a contact never changes an issued invoice's frozen customer. Each action accepts only its own fields (\* required): upsert(address, city, country, email, iban, id, is\_customer, is\_supplier, kind, name, notes, phone, postal\_code, province, tax\_id); merge(source\_id\*, target\_id\*); delete(id\*).

**Availability:** Autónomo / Empresa.

**Access:** Live in the Melso app and over MCP for a signed-in person. Where the partner REST API covers the same area, that path is private beta until Melso enables your account. See [Access and pricing](https://docs.melso.ai/api/access.md).

The live tool list is authoritative: the company's plan and your role can narrow this contract. [Understand access](https://docs.melso.ai/mcp/permissions.md).

## When to use

Use `contacts` for `delete`, `merge`, `upsert`. Use [`contacts_read`](https://docs.melso.ai/mcp/tools/contacts-read) for the companion actions. The live tool list determines availability.

## Input

```json theme={null}
{
  "additionalProperties": false,
  "oneOf": [
    {
      "additionalProperties": false,
      "properties": {
        "action": {
          "const": "upsert"
        },
        "address": {
          "description": "Street, number, floor and door.",
          "type": "string"
        },
        "city": {
          "description": "Town or city.",
          "type": "string"
        },
        "country": {
          "description": "Two-letter country of the tax ID and the address, ES by default.",
          "type": "string"
        },
        "email": {
          "description": "Email address invoices go to.",
          "type": "string"
        },
        "iban": {
          "description": "A supplier's IBAN, where its invoices are paid.",
          "type": "string"
        },
        "id": {
          "description": "The contact to change, from list; omit to add one.",
          "type": "string"
        },
        "is_customer": {
          "description": "Whether the company invoices it. A new contact is a customer unless is_supplier is true.",
          "type": "boolean"
        },
        "is_supplier": {
          "description": "Whether it invoices the company.",
          "type": "boolean"
        },
        "kind": {
          "description": "company for a business, professional for an autónomo, individual for a private person. Omit it to have Melso tell it from the tax ID.",
          "enum": [
            "company",
            "professional",
            "individual"
          ],
          "type": "string"
        },
        "name": {
          "description": "Legal name, or the person's full name.",
          "type": "string"
        },
        "notes": {
          "description": "Anything else worth keeping about it.",
          "type": "string"
        },
        "phone": {
          "description": "Phone number.",
          "type": "string"
        },
        "postal_code": {
          "description": "Postal or ZIP code.",
          "type": "string"
        },
        "province": {
          "description": "Province, state or region.",
          "type": "string"
        },
        "tax_id": {
          "description": "NIF, CIF, NIE, EU VAT number or a foreign tax ID such as a US EIN, as written.",
          "type": "string"
        }
      },
      "required": [
        "action"
      ],
      "type": "object"
    },
    {
      "additionalProperties": false,
      "properties": {
        "action": {
          "const": "merge"
        },
        "source_id": {
          "description": "Duplicate contact id to merge away.",
          "type": "string"
        },
        "target_id": {
          "description": "Contact id to keep, with the name and populated fields the person chose.",
          "type": "string"
        }
      },
      "required": [
        "action",
        "source_id",
        "target_id"
      ],
      "type": "object"
    },
    {
      "additionalProperties": false,
      "properties": {
        "action": {
          "const": "delete"
        },
        "id": {
          "description": "The contact's id, from list.",
          "type": "string"
        }
      },
      "required": [
        "action",
        "id"
      ],
      "type": "object"
    }
  ],
  "properties": {
    "action": {
      "enum": [
        "upsert",
        "merge",
        "delete"
      ],
      "type": "string"
    },
    "address": {
      "description": "Street, number, floor and door.",
      "type": "string"
    },
    "city": {
      "description": "Town or city.",
      "type": "string"
    },
    "country": {
      "description": "Two-letter country of the tax ID and the address, ES by default.",
      "type": "string"
    },
    "email": {
      "description": "Email address invoices go to.",
      "type": "string"
    },
    "iban": {
      "description": "A supplier's IBAN, where its invoices are paid.",
      "type": "string"
    },
    "id": {
      "anyOf": [
        {
          "description": "The contact to change, from list; omit to add one.",
          "type": "string"
        },
        {
          "description": "The contact's id, from list.",
          "type": "string"
        }
      ]
    },
    "is_customer": {
      "description": "Whether the company invoices it. A new contact is a customer unless is_supplier is true.",
      "type": "boolean"
    },
    "is_supplier": {
      "description": "Whether it invoices the company.",
      "type": "boolean"
    },
    "kind": {
      "description": "company for a business, professional for an autónomo, individual for a private person. Omit it to have Melso tell it from the tax ID.",
      "enum": [
        "company",
        "professional",
        "individual"
      ],
      "type": "string"
    },
    "name": {
      "description": "Legal name, or the person's full name.",
      "type": "string"
    },
    "notes": {
      "description": "Anything else worth keeping about it.",
      "type": "string"
    },
    "phone": {
      "description": "Phone number.",
      "type": "string"
    },
    "postal_code": {
      "description": "Postal or ZIP code.",
      "type": "string"
    },
    "province": {
      "description": "Province, state or region.",
      "type": "string"
    },
    "source_id": {
      "description": "Duplicate contact id to merge away.",
      "type": "string"
    },
    "target_id": {
      "description": "Contact id to keep, with the name and populated fields the person chose.",
      "type": "string"
    },
    "tax_id": {
      "description": "NIF, CIF, NIE, EU VAT number or a foreign tax ID such as a US EIN, as written.",
      "type": "string"
    }
  },
  "required": [
    "action"
  ],
  "type": "object"
}
```

## Actions

The tool's schema combines the fields of every action. Each action accepts only its own fields below; send `action` with them.

### Write actions

These actions change data. The server lists them only with a plan that includes the tools.

> [accordion] delete
>
> Delete a contact the person asks to remove. Refused if an invoice names it: merge duplicates instead. Existing income, expenses and their evidence are retained.
>
> ```json theme={null}
> {
>   "additionalProperties": false,
>   "properties": {
>     "id": {
>       "description": "The contact's id, from list.",
>       "type": "string"
>     }
>   },
>   "required": [
>     "id"
>   ],
>   "type": "object"
> }
> ```

> [accordion] merge
>
> Merge duplicate contacts when the person asks. Read both first and choose which id to keep as target\_id. Keeps the target's populated fields, fills missing data, combines customer/supplier roles and notes, moves invoice associations and remembers the source's identity for income, expenses and future document intake. Fiscal documents and posted history stay unchanged. Different nonempty fiscal identities are refused. Retrying the same source and target is safe.
>
> ```json theme={null}
> {
>   "additionalProperties": false,
>   "properties": {
>     "source_id": {
>       "description": "Duplicate contact id to merge away.",
>       "type": "string"
>     },
>     "target_id": {
>       "description": "Contact id to keep, with the name and populated fields the person chose.",
>       "type": "string"
>     }
>   },
>   "required": [
>     "source_id",
>     "target_id"
>   ],
>   "type": "object"
> }
> ```

> [accordion] upsert
>
> Save what the person tells you about a customer or supplier, so it is there next time. With id, only the fields given change (an empty string clears one). Without id, name is required and a contact with the same tax ID is completed instead of duplicated: the fields given replace its own, empty ones keep them and is\_customer or is\_supplier true adds that role. Never invent a value.
>
> ```json theme={null}
> {
>   "additionalProperties": false,
>   "properties": {
>     "address": {
>       "description": "Street, number, floor and door.",
>       "type": "string"
>     },
>     "city": {
>       "description": "Town or city.",
>       "type": "string"
>     },
>     "country": {
>       "description": "Two-letter country of the tax ID and the address, ES by default.",
>       "type": "string"
>     },
>     "email": {
>       "description": "Email address invoices go to.",
>       "type": "string"
>     },
>     "iban": {
>       "description": "A supplier's IBAN, where its invoices are paid.",
>       "type": "string"
>     },
>     "id": {
>       "description": "The contact to change, from list; omit to add one.",
>       "type": "string"
>     },
>     "is_customer": {
>       "description": "Whether the company invoices it. A new contact is a customer unless is_supplier is true.",
>       "type": "boolean"
>     },
>     "is_supplier": {
>       "description": "Whether it invoices the company.",
>       "type": "boolean"
>     },
>     "kind": {
>       "description": "company for a business, professional for an autónomo, individual for a private person. Omit it to have Melso tell it from the tax ID.",
>       "enum": [
>         "company",
>         "professional",
>         "individual"
>       ],
>       "type": "string"
>     },
>     "name": {
>       "description": "Legal name, or the person's full name.",
>       "type": "string"
>     },
>     "notes": {
>       "description": "Anything else worth keeping about it.",
>       "type": "string"
>     },
>     "phone": {
>       "description": "Phone number.",
>       "type": "string"
>     },
>     "postal_code": {
>       "description": "Postal or ZIP code.",
>       "type": "string"
>     },
>     "province": {
>       "description": "Province, state or region.",
>       "type": "string"
>     },
>     "tax_id": {
>       "description": "NIF, CIF, NIE, EU VAT number or a foreign tax ID such as a US EIN, as written.",
>       "type": "string"
>     }
>   },
>   "type": "object"
> }
> ```

## Output

`upsert` returns the saved contact. `merge` returns the kept contact after combining compatible duplicate identities; fiscal documents remain unchanged. `delete` returns a deletion receipt and refuses a contact named by an invoice.

The result uses MCP `content` blocks; JSON payloads are encoded in text and may also appear in `structuredContent`. Check `isError` before reading a success payload. When the server declares an `outputSchema`, it is reproduced below. Check the action result and its declared fields before reporting success.

### Declared output schema

```json theme={null}
{
  "anyOf": [
    {
      "properties": {
        "contact": {
          "properties": {
            "address": {
              "type": "string"
            },
            "city": {
              "type": "string"
            },
            "country": {
              "type": "string"
            },
            "email": {
              "type": "string"
            },
            "iban": {
              "type": "string"
            },
            "id": {
              "type": "string"
            },
            "is_customer": {
              "type": "boolean"
            },
            "is_supplier": {
              "type": "boolean"
            },
            "kind": {
              "type": "string"
            },
            "name": {
              "type": "string"
            },
            "notes": {
              "type": "string"
            },
            "phone": {
              "type": "string"
            },
            "postal_code": {
              "type": "string"
            },
            "province": {
              "type": "string"
            },
            "tax_id": {
              "type": "string"
            }
          },
          "required": [
            "id",
            "name",
            "is_customer",
            "is_supplier"
          ],
          "type": "object"
        },
        "merged": {
          "type": "boolean"
        },
        "repeated": {
          "type": "boolean"
        }
      },
      "required": [
        "contact"
      ],
      "type": "object"
    },
    {
      "properties": {
        "contact": {
          "properties": {
            "address": {
              "type": "string"
            },
            "city": {
              "type": "string"
            },
            "country": {
              "type": "string"
            },
            "email": {
              "type": "string"
            },
            "iban": {
              "type": "string"
            },
            "id": {
              "type": "string"
            },
            "is_customer": {
              "type": "boolean"
            },
            "is_supplier": {
              "type": "boolean"
            },
            "kind": {
              "type": "string"
            },
            "name": {
              "type": "string"
            },
            "notes": {
              "type": "string"
            },
            "phone": {
              "type": "string"
            },
            "postal_code": {
              "type": "string"
            },
            "province": {
              "type": "string"
            },
            "tax_id": {
              "type": "string"
            }
          },
          "required": [
            "id",
            "name",
            "is_customer",
            "is_supplier"
          ],
          "type": "object"
        },
        "merged": {
          "type": "boolean"
        },
        "repeated": {
          "type": "boolean"
        }
      },
      "required": [
        "contact"
      ],
      "type": "object"
    },
    {
      "properties": {},
      "type": "object"
    }
  ],
  "type": "object"
}
```

## Example

Use the actions of this tool in the order shown; its companion tool covers the other actions. These are the `arguments` of each call, in order.

**1. Save a new customer**

```json theme={null}
{
  "action": "upsert",
  "name": "Example Studio SL",
  "kind": "company",
  "tax_id": "B00000000",
  "address": "Calle Mayor 1, 28013 Madrid",
  "email": "billing@example.com"
}
```

The first call as a request. Use an OAuth access token issued for this MCP resource and replace the example identifiers with values from your own company. Write actions change data.

```bash theme={null}
curl --fail-with-body https://mcp.melso.ai/mcp \
  -H "Authorization: Bearer $MELSO_MCP_TOKEN" \
  -H "Content-Type: application/json" \
  -H "Accept: application/json, text/event-stream" \
  --data-binary @- <<'JSON'
{
  "jsonrpc": "2.0",
  "id": 1,
  "method": "tools/call",
  "params": {
    "name": "contacts",
    "arguments": {
      "action": "upsert",
      "name": "Example Studio SL",
      "kind": "company",
      "tax_id": "B00000000",
      "address": "Calle Mayor 1, 28013 Madrid",
      "email": "billing@example.com"
    }
  }
}
JSON
```


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.