Skip to main content
Glama
clement-igonet

apec-mcp

APEC MCP Server

MCP (Model Context Protocol) server that exposes the APEC candidate-profile API as tools for any MCP-compatible AI assistant.


API Analysis

API Type

Proprietary REST / JSON over HTTPS.
Not publicly documented. Discovered via browser network capture (HAR files).
Base URL: https://www.apec.fr/cms/webservices/

Authentication

Email/password auto-login — no manual cookie handling required.

The server posts credentials to /.apec-login.do at first use and caches the resulting session cookies in ~/.apec_session.json. On 401/403 the session is automatically invalidated and a fresh login is attempted before retrying.

Env var

Purpose

APEC_EMAIL

APEC account email

APEC_PASSWORD

APEC account password

APEC_ID_COMPTE_CADRE

Numeric account ID (from your APEC profile URL)

APEC_ID_PROFIL_CADRE

Numeric profile ID (from your APEC profile URL)

APEC_SESSION_FILE

Override session cache path (default: ~/.apec_session.json)

APEC_COOKIES

Manual cookie override — takes precedence over auto-login (fallback if DataDome blocks login)

Reflection / Introspection

There is no public API schema (no OpenAPI spec, no GraphQL introspection).
The API was reverse-engineered from three browser sessions:

  • www.apec.fr.har — initial profile creation

  • www2.apec.fr.har — portfolio/strengths editing

  • www3.apec.fr.har — full profile editing (business card, photo upload, reference data)

The backend appears to be a Java Spring application (JSESSIONID, Jahia CMS static assets).


Related MCP server: resume-mcp

API Endpoints

Profile

Method

Path

Description

GET

/profilCadre/{idCompte}/complete

Full profile (the canonical object)

POST

/profilCadre/updateExperiencesEtFormations

Save experiences + education

POST

/profilCadre/updateInformationsComplementaires

Save job-search preferences

POST

/profilCadre/updateAtouts

Save skills + strengths

POST

/profilCadre/carteDeVisite

Save personal / contact info

POST

/profilCadre/validation/{SECTION}

Validate before saving

GET

/profilCadre/shouldDisplayEncart

UI display flag

GET

/profilCadre/photoUploadFolders

Photo upload paths

Stats

Method

Path

Description

GET

/profilVu/{idProfil}/nombreVuesDepuisPublication

Total profile views

GET

/profilVu/{idProfil}/dureePublication

Days since publication

GET

/profilVu/{idProfil}/tendanceVues

Views trend (float)

POST

/echangeProfil/count

Unread recruiter messages

POST

/panierProfil/countInterlocuteursRetenir

Saved contacts count

Search / Autocomplete

Method

Path

Description

GET

/autocompletion/distinctMetierAutocomplete

Job-title search

GET

/autocompletion/autocomplete

General search

Reference Data

Method

Path

Description

POST

/referentielstatique/presentations/visuels/liste/hierarchie

Enum lists (869 entries)

GET

/referentielstatique/fonctions/metiers/{id}/organisation

Métier taxonomy node

GET

/referentielstatique/presentations/code/LISTE_MONDE/visuels

Country list

Identification & CV

Method

Path

Description

GET

/identification/apecuser

Current user info

GET

/cv/cvFichiersByIdCompte

Uploaded CV files

GET

/pushRecoOffre/abonnement/cadre/{id}

Job-recommendation subscription

Job Offers

Method

Path

Description

POST

/affiniteOrchestration/matching-candidat

AI-matched offers for the candidate

GET

/offre/public

Full offer details by numeroOffre

POST

/rechercheAffinite/rebond

Similar/related offers

GET

/pageEntreprise/public/{id}

Public company profile

Applications & Saved Jobs

Method

Path

Description

POST

/candidature/siteRh

Submit an APEC-hosted application

POST

/candidature/liste

List past applications

POST

/candidature/liste/count

Check if already applied to an offer

POST

/panierOffre/liste

List saved/bookmarked offers


Data Model (TypeSpec)

import "@typespec/rest";
import "@typespec/http";

using TypeSpec.Rest;
using TypeSpec.Http;

// ── Shared ──────────────────────────────────────────────────────────────

model Audit {
  dateCreation: int64;        // epoch ms
  dateModification: int64 | null;
  utilisateurCreation: string;
  utilisateurModification: string | null;
}

// ── Reference / enum entries ─────────────────────────────────────────────

model ReferenceItem {
  codePresentation: string;
  idNomenclature: int64;
  codeNomenclature: string;
  idOrganisation: int64;
  idOrganisationParent: int64 | null;
  libelle: string;
  niveau: int32;
  ordre: int32;
}

// ── Sub-models ───────────────────────────────────────────────────────────

model Experience {
  intitulePoste: string;
  idNomFonction: int64;
  idNomMetier: int64;
  dateEntree: string;           // ISO 8601
  dateSortie: string | null;
  nomEntreprise: string;
  expNonCadre: boolean;
  numeroOrdre: int32;
  audit: Audit;
}

model Formation {
  intituleFormation: string;
  dateEntree: string;           // ISO 8601
  dateSortie: string | null;
  idNomDiscipline: string;
  idNomNiveau: string;
  organismeFormation: string | null;
  numeroOrdre: int32;
  audit: Audit;
}

enum CompetenceType {
  LANGUE,
  SAVOIR_ETRE,
  TECHNIQUE,
  METIER,
}

model Competence {
  libelle: string;
  type: CompetenceType;
  idNomCompetence: int64;
  idNomNiveau: int64 | null;
  miseEnAvant: boolean;
  idProfilCadre: int64;
  audit: Audit;
  id: int64;
}

model AdressePostale {
  adresseNumeroEtVoie: string;
  adresseCodePostal: string;
  adresseVille: string;
  adresseBatimentImmResidence: string | null;
  adresseComplementAdresse: string | null;
  idPays: int64;
  audit: Audit;
  id: int64;
}

model SouhaitSecteur   { idNomSecteurActivite: int64; audit: Audit; id: int64; }
model SouhaitFonction  { idNomFonction: int64; idNomMetier: int64; audit: Audit; id: int64; }
model SouhaitContrat   { idNomTypeContrat: int64; audit: Audit; id: int64; }
model SouhaitEntreprise{ idNomTailleEntreprise: int64; audit: Audit; id: int64; }
model SouhaitTemps     { idNomTempsTravail: int64; audit: Audit; id: int64; }
model SouhaitMode      { idNomModeTravail: int64; audit: Audit; id: int64; }
model SouhaitLieu      { idNomLieu: int64; distance: int32 | null; audit: Audit; id: int64; }

// ── Full profile ─────────────────────────────────────────────────────────

model ProfilCadre {
  id: int64;
  idProfilCadre: int64;
  idCompteCadre: int64;
  idNomStatut: int64;
  idNomStatutCandidat: int64;

  // Personal info
  idNomCivilite: int64;
  nom: string;
  prenom: string;
  dateNaissance: int64;           // epoch ms
  adressePostale: AdressePostale;
  adresseEmail: string;
  numeroTelephoneMobile: string;
  lienLinkedin: string | null;
  photo: string | null;

  // Professional summary
  metierSouhaite: string;
  objectifProfessionnel: string | null;
  pointsClesProfessionnels: string | null;
  idNomAnneesExperience: int64;
  idNomDelaiDisponibilite: int64;
  remunerationMinimale: float32;
  indicateurMasquerSalaire: boolean;
  pretPourRecrutement: boolean;

  // Preferences
  souhaitsSecteurs: SouhaitSecteur[];
  souhaitsFonctions: SouhaitFonction[];
  souhaitsContrats: SouhaitContrat[];
  souhaitsEnts: SouhaitEntreprise[];
  souhaitsTemps: SouhaitTemps[];
  souhaitsModes: SouhaitMode[];
  souhaitsLieux: SouhaitLieu[];

  // Experiences & formations
  experiencesCles: Experience[];
  formationsCles: Formation[];

  // Skills
  competences: Competence[];
  atouts: string[];
  portfolios: unknown[];

  // CV
  idCvFichier: int64 | null;

  // Completion indicators
  tauxRemplissage: int32;
  indicateurCompletCompetence: boolean;
  indicateurCompletCompMea: boolean;
  indicateurCompletPortfolio: boolean;

  // Versioning
  numeroVersion: int32;
  numeroVersionCadre: int32;
  audit: Audit;
  auditCadre: Audit;
}

// ── User identity ────────────────────────────────────────────────────────

model ApecUser {
  id: string;
  numeroCompte: string;
  nom: string;
  prenom: string;
  email: string;
  cadre: boolean;
  actif: boolean;
  token: string;
  sessionId: string;
}

MCP Tools

Tool

APEC endpoint

Description

get_user_info

GET /identification/apecuser

Authenticated user details

get_profile

GET /profilCadre/{id}/complete

Full profile (use as base for updates)

get_profile_stats

GET /profilVu/… × 3

Views, duration, trend

get_cv_files

GET /cv/cvFichiersByIdCompte

Uploaded CVs

get_unread_messages_count

POST /echangeProfil/count

Unread recruiter messages

validate_section

POST /profilCadre/validation/{SECTION}

Validate before saving

update_experiences_formations

POST /profilCadre/updateExperiencesEtFormations

Experiences + education

update_informations_complementaires

POST /profilCadre/updateInformationsComplementaires

Job-search preferences

update_atouts

POST /profilCadre/updateAtouts

Skills + strengths

update_carte_de_visite

POST /profilCadre/carteDeVisite

Personal / contact info

search_metiers

GET /autocompletion/distinctMetierAutocomplete

Job-title autocomplete

autocomplete

GET /autocompletion/autocomplete

General search

get_metier_organisation

GET /referentielstatique/fonctions/…

Métier taxonomy

get_reference_lists

POST /referentielstatique/…/hierarchie

Enum reference data

get_matching_jobs

POST /affiniteOrchestration/matching-candidat

AI-matched job offers (paginated)

get_job_offer

GET /offre/public

Full offer details

get_similar_jobs

POST /rechercheAffinite/rebond

Related offers

get_company_info

GET /pageEntreprise/public/{id}

Public company profile

apply_to_job

POST /candidature/siteRh

Submit APEC-hosted application

list_applications

POST /candidature/liste

Past applications (paginated)

check_applied_to_offer

POST /candidature/liste/count

Check if already applied

list_saved_jobs

POST /panierOffre/liste

Saved/bookmarked offers

refresh_session

POST /.apec-login.do

Force re-login and return user info

Update pattern

All update endpoints require the complete profile object (not a partial patch).

profile = get_profile()
profile["experiencesCles"].append({...})
update_experiences_formations(profile)

Key Use Case — Fill Profile from LinkedIn or CV

The intended end-to-end workflow:

1. [LinkedIn MCP] get_my_profile()           → raw LinkedIn data
   OR parse CV text (PDF / plain text)

2. [APEC MCP]     get_reference_lists([…])  → resolve enum IDs
                  search_metiers(q=…)        → find idNomMetier / idNomFonction

3. AI assistant maps fields:
     LinkedIn title      → metierSouhaite + experiencesCles[].intitulePoste
     LinkedIn positions  → experiencesCles[]
     LinkedIn education  → formationsCles[]
     LinkedIn skills     → competences[]
     LinkedIn location   → adressePostale + souhaitsLieux[]

4. [APEC MCP]     get_profile()                     → fetch current profile
                  update_experiences_formations(…)  → save
                  update_informations_complementaires(…)
                  update_atouts(…)
                  update_carte_de_visite(…)

Setup & Run

Prerequisites

  • uv installed

Install

git clone <repo>
cd apec-mcp
uv sync
cp .env.example .env
# Fill in APEC_EMAIL, APEC_PASSWORD, APEC_ID_COMPTE_CADRE, APEC_ID_PROFIL_CADRE

Local development (SSE)

uv run apec-mcp               # SSE on http://localhost:8080/sse

Pass credentials directly in the env block. Use the absolute path to the venv binary so the config works regardless of which directory the MCP client opens.

{
  "mcpServers": {
    "apec": {
      "command": "/path/to/apec-mcp/.venv/bin/apec-mcp",
      "args": [],
      "env": {
        "MCP_TRANSPORT": "stdio",
        "APEC_EMAIL": "you@example.com",
        "APEC_PASSWORD": "yourpassword",
        "APEC_ID_COMPTE_CADRE": "123456789",
        "APEC_ID_PROFIL_CADRE": "1234567"
      }
    }
  }
}

For Claude Code place this block in ~/.claude.json under mcpServers so all sessions share it.

Docker (SSE mode, optional)

docker build -t apec-mcp:latest .
docker run -d --name apec-mcp-server -p 8081:8080 --env-file .env \
  -e MCP_TRANSPORT=sse apec-mcp:latest

Then point your MCP client at http://localhost:8081/sse.

docker compose may fail to resolve build-cache image digests in some container-in-container environments (OrbStack socktainer, Docker-in-Docker). Plain docker run is more reliable in those setups.


Session Refresh

Session cookies are cached automatically in ~/.apec_session.json and refreshed on 401/403. No manual action is normally needed.

If auto-login is blocked by DataDome:

  1. Open https://www.apec.fr → log in manually

  2. DevTools → Network → any /cms/webservices/* request → Request Headers → Cookie

  3. Add APEC_COOKIES=<value> to .env — this overrides auto-login

F
license - not found
-
quality - not tested
B
maintenance

Maintenance

Maintainers
Response time
Release cycle
Releases (12mo)
Commit activity

Resources

Unclaimed servers have limited discoverability.

Looking for Admin?

If you are the server author, to access and configure the admin panel.

Latest Blog Posts

MCP directory API

We provide all the information about MCP servers via our MCP API.

curl -X GET 'https://glama.ai/api/mcp/v1/servers/clement-igonet/apec-mcp'

If you have feedback or need assistance with the MCP directory API, please join our Discord server