Skip to main content
Glama
cydgxbriel

hr-agent-mcp

by cydgxbriel

🕐 HR Agent MCP

Conversational HR agent that replaces static time-tracking screens with a chat interface — built with MCP, LangGraph, RAG and BigQuery.

🔗 Live demo: hr-agent-mcp-cyd.streamlit.app (password: on request) · CI

What it does

The agent handles four kinds of natural-language requests, all through chat:

  • Time-punch queries — "how were Ana's punches over the last two weeks?" returns the history, with late arrivals and incomplete punches highlighted.

  • Policy questions, with sources — "what is the lateness tolerance?" is answered with RAG over the company's HR policies, citing the source document rather than a generic summary.

  • Adjustment approval with human confirmation — write requests (for example, approving a time-punch adjustment) go through an explicit confirmation card before anything changes in the database, and are recorded in an audit trail.

  • Analytics on BigQuery — analytical questions ("which team accumulated the most overtime per month?") generate SQL via LLM, which passes through a governance layer before touching the warehouse.

▶️ Try it live: hr-agent-mcp-cyd.streamlit.app — or follow the 3-minute walkthrough.

Related MCP server: HRizzle-HR-Assist

Architecture

flowchart TD
    UI[Streamlit — chat + MCP panel] --> AG[LangGraph — ReAct agent\nmemory + human-in-the-loop]
    AG -->|MCP stdio| SRV[MCP server — FastMCP]
    SRV --> T1[consultar_batidas] --> DB[(SQLite\noperational)]
    SRV --> T2[list/approve adjustments] --> DB
    T2 --> AUD[(audit_log)]
    SRV --> T3[consultar_politica] --> RAG[FAISS — HR policies]
    SRV --> T4[analytics_rh] --> BQ[(BigQuery\nrh_analytics)]
    ETL[Python ETL\nextract→transform→load] --> DB
    ETL --> BQ

The system deliberately separates two worlds: the operational side (SQLite, read-write, low latency, day-to-day data such as punches and adjustments) and the analytical side (BigQuery, read-only, aggregated data for management questions). This separation keeps heavy analytical queries from competing with the transactional path, and keeps the warehouse as a derived, auditable copy — never a source of truth for writes.

Technical decisions

  • Tools behind an MCP server (stdio) rather than in-process functions: the agent and the tool layer evolve independently, and any MCP-compatible client can reuse the same server.

  • Every write goes through interrupt — the graph pauses and hands control back to the UI, which requires explicit human confirmation — and is recorded in audit_log before it counts as done. The agent never writes silently.

  • LLM-generated SQL passes a governance layer before touching BigQuery, instead of trusting the model with raw warehouse access.

  • Two-layer eval scoring — deterministic checks (tool choice, regex, gate state) plus LLM-as-judge only for what string matching cannot cover.

Capabilities demonstrated

Capability

Where in the code

MCP (server + client)

mcp_server/server.py, agent/graph.py

Agent orchestration (LangGraph)

agent/graph.py

Human-in-the-loop (interrupt)

agent/graph.py (_com_confirmacao)

RAG (FAISS + embeddings)

rag/index.py, data/politicas/

ETL (extract→transform→load)

etl/

BigQuery + SQL governance

mcp_server/analytics.py, core/bq.py

Agent evaluation (evals)

evals/, EVALS.md

Python APIs / tests / CI

mcp_server/db.py, tests/, .github/workflows/

Evaluation (evals)

The agent is evaluated end-to-end by a 28-case suite across 8 categories (routing, operational, policies, analytics, write gate, governance, disambiguation and cross-source questions), with two-layer scoring — deterministic (tool chosen, regex, gate state) plus LLM-as-judge for what string matching cannot cover. Write cases run against an isolated copy of the database. Run with uv run python -m evals.run; results live in EVALS.md.

Running locally

git clone https://github.com/cydgxbriel/hr-agent-mcp.git && cd hr-agent-mcp
cp .env.example .env && uv sync        # fill in OPENAI_API_KEY
uv run python -m etl.pipeline && uv run streamlit run app/main.py

APP_PASSWORD is optional in development (it protects the app when publicly exposed). BigQuery is optional too: without configured credentials the agent keeps working and the analytics tool degrades gracefully, reporting the feature as unavailable instead of failing.

BigQuery (optional)

  1. Create a project in the GCP Sandbox (free, no credit card).

  2. Create a service account with BigQuery Data Editor + BigQuery Job User roles in that project (Data Editor creates datasets; Job User runs load jobs and queries — least privilege).

  3. Download the service account's JSON key.

  4. Set GCP_PROJECT_ID in .env to the new project id — without this variable the BigQuery client stays disabled even with credentials configured.

  5. Point GOOGLE_APPLICATION_CREDENTIALS at the key file path (local use) or paste the file contents into GCP_SERVICE_ACCOUNT_JSON (Streamlit Cloud, which has no persistent filesystem).

  6. Run uv run python -m etl.pipeline to load the rh_analytics dataset (table agregados_mensais) into BigQuery.

Data

All data is 100% synthetic, generated with Faker (seed 42): employees, time punches, adjustments and HR policies are fictional personas and documents created exclusively for this demonstration. No real data from any company is used or referenced anywhere in the project.

Stack

  • Python 3.11+

  • uv (environment and dependency management)

  • mcp ≥1.2 / FastMCP (stdio MCP server)

  • LangGraph ≥0.2.60 (ReAct agent orchestration)

  • langchain-mcp-adapters ≥0.1 (the agent's MCP client)

  • langchain-openai ≥0.2.10 (gpt-4o-mini)

  • langchain-community ≥0.3.10 / FAISS ≥1.8 (RAG)

  • pandas ≥2.2 (ETL)

  • Faker ≥30 (synthetic data generation)

  • google-cloud-bigquery ≥3.25

  • Streamlit ≥1.40 (chat interface)

  • pytest ≥8 (35 tests)

  • ruff (lint)

Available Tools

5 tools
analytics_rhA

Executa uma consulta analítica SELECT no data warehouse (BigQuery).

Use para perguntas agregadas sobre a equipe: total de horas extras por mês, evolução de atrasos, batidas incompletas por equipe. Escreva SQL padrão BigQuery usando exclusivamente esta tabela: rh_analytics.agregados_mensais — colunas: equipe STRING (Produto, Engenharia, Comercial), mes STRING 'YYYY-MM', total_atraso_minutos INT64, total_hora_extra_minutos INT64, batidas_incompletas INT64, colaboradores INT64. Somente SELECT é aceito; a consulta passa por validação de governança. Não use WITH/CTE, ponto e vírgula nem comentários — apenas um SELECT direto.

ParametersJSON Schema
NameRequiredDescriptionDefault
consulta_sqlYes

Output Schema

ParametersJSON Schema
NameRequiredDescription
resultYes

TDQS

A4.5/5.0
Behavior4/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

No annotations provided, so description carries full burden. Discloses constraints: SELECT only, no CTEs/semicolons/comments, and governance validation. Does not mention rate limits or authentication, but adds valuable behavioral context.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness5/5

Is the description appropriately sized, front-loaded, and free of redundancy?

Every sentence serves a purpose: action, usage, schema, constraints. No wasted words; front-loaded with the core function.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness4/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

Covers purpose, usage, SQL details, and constraints. Output schema exists, so return values need not be described. Could explicitly state no side effects, but overall complete for a SQL query tool.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters5/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema coverage is 0%, but description fully compensates by detailing the required SQL content, exact table and columns, and formatting constraints. Adds critical meaning beyond the generic schema title.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

Specific verb 'Executa' and resource 'consulta analítica SELECT no data warehouse (BigQuery)'. Clearly distinguishes from sibling tools like 'aprovar_ajuste' (approvals) and 'consultar_batidas' (time tracking).

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines4/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

Explicit use cases for aggregate queries (horas extras, atrasos, batidas incompletas) and specifies the table and columns. Lacks explicit when-not-to-use or alternative pointers, but sibling context helps.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

aprovar_ajusteA

Aprova um ajuste de ponto pendente. AÇÃO DE ESCRITA com auditoria.

Use somente quando a gestora pedir explicitamente para aprovar um ajuste. Exige o id do ajuste (veja listar_ajustes_pendentes) e uma justificativa. A aprovação corrige a batida e registra na trilha de auditoria.

ParametersJSON Schema
NameRequiredDescriptionDefault
ajuste_idYes
justificativaYes

Output Schema

ParametersJSON Schema
NameRequiredDescription
resultYes

TDQS

A4.2/5.0
Behavior4/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

With no annotations provided, the description discloses that it is a WRITE ACTION with audit, and explains that approval corrects the clock-in/out and records in the audit trail, sufficient behavioral context.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness5/5

Is the description appropriately sized, front-loaded, and free of redundancy?

The description is three sentences long, front-loaded with the core purpose, and every sentence earns its place (purpose, usage condition, behavioral note).

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness4/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

Given the tool's simplicity (2 parameters, no annotations, output schema exists), the description adequately covers purpose, usage, inputs, and behavior, though output details are left to the schema.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters3/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema description coverage is 0%, but the description adds meaning by stating that ajuste_id comes from listar_ajustes_pendentes and that justificativa is required. However, it does not elaborate on formats or constraints.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

The description clearly states 'Approve a pending time adjustment' with a specific verb and resource, distinguishing it from sibling tools like listar_ajustes_pendentes which lists adjustments.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines4/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

The description explicitly states 'Use only when the manager explicitly asks to approve an adjustment' and directs the user to listar_ajustes_pendentes to obtain the adjustment ID, providing clear when-to-use guidance.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

consultar_batidasA

Consulta as batidas de ponto de um colaborador da equipe num período.

Use para perguntas sobre horários, atrasos, horas extras ou batidas faltantes de uma pessoa específica. Aceita nome parcial (ex.: 'Bruno'). Datas no formato YYYY-MM-DD. O período dos dados vai de maio a julho de 2026.

ParametersJSON Schema
NameRequiredDescriptionDefault
data_fimYes
data_inicioYes
nome_colaboradorYes

Output Schema

ParametersJSON Schema
NameRequiredDescription
resultYes

TDQS

A4.4/5.0
Behavior4/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

With no annotations, the description properly discloses important behaviors: accepts partial names ('Aceita nome parcial'), expects date format YYYY-MM-DD, and notes the data range (maio a julho de 2026). This adds value beyond the schema.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness5/5

Is the description appropriately sized, front-loaded, and free of redundancy?

Three sentences, each purposeful: purpose, usage scenarios, and technical details. No redundant or unnecessary information. Efficiently structured.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness4/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

Given three required parameters, no annotations, and an output schema present, the description adequately covers purpose, usage, parameter details, and data constraints. Lacks explanation of absence handling, but output schema likely covers return structure.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters4/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema coverage is 0%, so description must compensate. It explains that 'nome_colaborador' accepts partial names, and date parameters use format YYYY-MM-DD within a specific period. This gives meaning to the three parameters beyond their schema titles.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

The description clearly states it consults time punches ('batidas de ponto') for a team member in a period, using specific verb 'Consulta'. This distinctly separates it from sibling tools like analytics_rh (HR analytics) or aprovar_ajuste (approve adjustments).

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines4/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

Explicitly says 'Use para perguntas sobre horários, atrasos, horas extras ou batidas faltantes de uma pessoa específica', providing clear when-to-use context. It doesn't explicitly state when not to use, but the sibling tool names imply alternatives for other tasks.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

consultar_politicaA

Busca trechos relevantes das políticas internas de RH (RAG).

Use para dúvidas sobre regras: tolerância de atraso, banco de horas, ajuste de batida, home office, advertências. Retorna trechos literais com a fonte; responda com base neles, citando a política.

ParametersJSON Schema
NameRequiredDescriptionDefault
perguntaYes

Output Schema

ParametersJSON Schema
NameRequiredDescription
resultYes

TDQS

A4.5/5.0
Behavior4/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

With no annotations provided, the description carries full behavioral disclosure. It states the tool returns literal excerpts with sources and instructs the agent to respond based on them citing the policy. It does not mention read-only behavior or authentication, but for a RAG search tool, the transparency is adequate.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness5/5

Is the description appropriately sized, front-loaded, and free of redundancy?

The description is very concise: two sentences that cover purpose, usage, and return value. It is front-loaded with the main action and every sentence adds value. No redundancy.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness5/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

Given the tool has only one parameter and the output schema exists (though not shown), the description covers what the tool does, when to use it, and what the output contains. It is complete for a simple RAG query tool.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters4/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

The input schema has one parameter 'pergunta' with no description (schema coverage 0%). The description compensates by indicating the parameter should be a question about HR rules and gives examples. While it doesn't detail syntax, it provides enough context for the parameter's purpose.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

The description clearly states the tool searches for relevant excerpts from internal HR policies using RAG. It lists specific examples like tolerância de atraso and banco de horas, making the purpose concrete. The sibling tools (analytics_rh, aprovar_ajuste, etc.) are distinct, so there is no confusion.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines4/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

The description explicitly says 'Use para dúvidas sobre regras' and provides a list of example use cases. However, it does not explicitly state when not to use this tool or compare it directly to siblings, though the sibling names imply different functions.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

listar_ajustes_pendentesA

Lista os ajustes de ponto aguardando aprovação da gestora.

Use quando a gestora perguntar o que está pendente, o que precisa aprovar, ou pedir a fila de ajustes. Retorna id, colaborador, data, campo a corrigir, valor proposto e motivo.

ParametersJSON Schema
NameRequiredDescriptionDefault

No parameters

Output Schema

ParametersJSON Schema
NameRequiredDescription
resultYes

TDQS

A4.5/5.0
Behavior4/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

Sem anotações, mas a descrição informa que retorna uma lista de ajustes pendentes (id, colaborador, data, etc.). Não menciona efeitos colaterais, mas é claramente uma leitura. Poderia ser mais explícito sobre não ser destrutivo.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness5/5

Is the description appropriately sized, front-loaded, and free of redundancy?

Duas frases, sem redundância. A primeira frase define o propósito, a segunda fornece contexto de uso e conteúdo do retorno. Front-loading perfeito.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness5/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

Para uma ferramenta simples e sem parâmetros, a descrição cobre o suficiente: o que faz, quando usar e o que retorna. A existência de output schema complementa.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters4/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Nenhum parâmetro. A descrição não precisa adicionar informações sobre parâmetros, pois o schema já cobre 100%. Baseline para 0 parâmetros é 4.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

Descrição específica: 'Lista os ajustes de ponto aguardando aprovação da gestora'. Verbo claro ('Lista') e recurso definido. Distingue-se dos irmãos como 'aprovar_ajuste' e 'consultar_batidas'.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines4/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

Explicitamente diz quando usar: 'Use quando a gestora perguntar o que está pendente, o que precisa aprovar, ou pedir a fila de ajustes'. Falta contraste direto com alternativas, mas fica implícito.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

Tool Schema Changelog

Recent tool additions, removals, and schema changes observed during successful MCP inspections.

  1. 5 tool updatesv0.1.0
    • First observedanalytics_rh
    • First observedaprovar_ajuste
    • First observedconsultar_batidas
    • First observedconsultar_politica
    • First observedlistar_ajustes_pendentes

TDQS

A4.4/5.0

Scored across 5 tools

Disambiguation5/5

Each tool targets a distinct aspect: aggregate analytics, individual punch queries, policy lookup, listing adjustments, and approving adjustments. There is no functional overlap.

Naming Consistency4/5

All names follow snake_case and imperative verb_noun pattern, but 'analytics_rh' mixes English verb with Portuguese noun, while others are fully Portuguese.

Tool Count5/5

Five tools cover the core HR agent tasks concisely without being too sparse or overwhelming. The count fits the scope well.

Completeness4/5

Covers analytics, individual queries, policy lookup, and adjustment workflow (list and approve). Missing a reject action for adjustments but otherwise complete for manager tasks.

Maintenance

ActivitySlowing
ResponsivenessNo issues

Related MCP Connectors

Related MCP Servers

  • F
    license
    Not graded
    quality
    D
    maintenance
    An MCP-powered HR management system that automates employee onboarding, leave tracking, meeting scheduling, and IT ticketing. It allows users to manage organizational workflows and administrative tasks through natural language interactions with Claude.
    2
    -
  • F
    license
    Not graded
    quality
    C
    maintenance
    An MCP server for interacting with an HR database, enabling querying employee data and HR operations via natural language.
    -
  • F
    license
    Not graded
    quality
    B
    maintenance
    Enables querying HR data like recent hires, employee details, departments, and PTO balances through natural language in an MCP client.
    -