Skip to main content
Glama
naranmunkh

Timely MCP Server

by naranmunkh
README.md
# Timely MCP Server

An [MCP](https://modelcontextprotocol.io) server that exposes the
[Timely.mn](https://developer.timely.mn/) v3 time-attendance API as tools for
Claude and any other MCP client.

Built for **UBCab Holding**. One self-contained file (`src/index.ts`) runs two ways:

- **Remote (Vercel)** — Vercel's Node framework invokes the file's default
  `(req, res)` handler. Live at `POST https://timely-mcp.vercel.app/mcp`,
  protected by a bearer token.
- **Local (stdio)** — when run directly (`node dist/index.js`), it speaks MCP
  over stdio for Claude Desktop.

## Tools

| Tool | Endpoint | Purpose |
| --- | --- | --- |
| `timely_employer_info` | `POST /v3/employer-info` | Company name lookup by 7-digit register |
| `timely_overview_attd` | `POST /v3/overview-attd` | Company-wide attendance report (paginated) |
| `timely_employee_attd` | `POST /v3/employee-attd` | One employee's attendance between two dates |
| `timely_employee_info` | `POST /v3/employee-info` | One employee's profile (name, salary, bank) |

Login (`POST /v3/login` → JWT) is automatic: the token is cached and refreshed
on a 401/403. Credentials are only required when a tool actually calls the API,
so `tools/list` works without them.

## Endpoints (deployed)

- `POST /mcp` — the MCP endpoint (bearer token required).
- `GET /health` — returns `{"status":"ok"}` (no auth).

## Environment variables

| Variable | Required | Notes |
| --- | --- | --- |
| `TIMELY_USERNAME` | yes (for API calls) | Timely API login |
| `TIMELY_PASSWORD` | yes (for API calls) | Timely API password |
| `TIMELY_MCP_AUTH_TOKEN` | yes (remote) | Secret clients send as `Bearer`. The POST endpoint fails closed without it. Generate: `openssl rand -hex 32` |
| `TIMELY_COMPANY_REGISTER` | no | Default 7-digit register |
| `TIMELY_BASE_URL` | no | Defaults to `https://api.timely.mn` |

## Use locally (Claude Desktop)

```bash
npm install
npm run build
```

```json
{
  "mcpServers": {
    "timely": {
      "command": "node",
      "args": ["/absolute/path/to/timely-mcp/dist/index.js"],
      "env": {
        "TIMELY_USERNAME": "ubcabholding",
        "TIMELY_PASSWORD": "your-password",
        "TIMELY_COMPANY_REGISTER": "1234567"
      }
    }
  }
}
```

## Connect to the remote endpoint

Three ways to authenticate (the endpoint accepts any of them):

**1. OAuth (recommended — nothing secret in the URL).** Add a custom connector
with just the URL `https://timely-mcp.vercel.app/mcp`. The client discovers the
OAuth metadata, opens a login page, and prompts for the access token
(`TIMELY_MCP_AUTH_TOKEN`). Implemented as a stateless OAuth 2.1 + PKCE server:
`/.well-known/oauth-protected-resource`, `/.well-known/oauth-authorization-server`,
`/register`, `/authorize`, `/token`. Auth codes and access tokens are HMAC-signed
blobs (no datastore).

**2. Header (Claude Desktop JSON config).**

```json
{
  "mcpServers": {
    "timely-remote": {
      "type": "http",
      "url": "https://timely-mcp.vercel.app/mcp",
      "headers": { "Authorization": "Bearer <TIMELY_MCP_AUTH_TOKEN>" }
    }
  }
}
```

**3. Token in URL path** (for clients that can't send a header):
`https://timely-mcp.vercel.app/mcp/<TIMELY_MCP_AUTH_TOKEN>`

Smoke test:

```bash
curl -s -X POST https://timely-mcp.vercel.app/mcp -H 'Content-Type: application/json' -H 'Accept: application/json, text/event-stream' -H 'Authorization: Bearer <TIMELY_MCP_AUTH_TOKEN>' -d '{"jsonrpc":"2.0","id":1,"method":"tools/list","params":{}}'
```

## Deployment notes

- Vercel auto-detects this repo as a **Node** project and runs `src/index.ts`'s
  default export as a serverless function — there is **no `vercel.json`** and no
  `/api` directory by design. Adding either reintroduced routing/entrypoint bugs.
- Every push to `main` auto-deploys via Vercel's Git integration.
- Verify the JWT field with `node --env-file=.env scripts/test-login.mjs`; if the
  token lives under a field other than `token`/`access_token`/`accessToken`/`jwt`,
  add it to `extractToken()` in `src/index.ts`.

## Security

The deployed URL + bearer token can read employee **salary and bank details**.
Treat both as secrets; rotate the token (`openssl rand -hex 32` → update the
Vercel env var → redeploy) if it leaks.

TDQS

A4.1/5.0

Scored across 4 tools

Disambiguation5/5

Each tool has a clearly distinct purpose: employee attendance, employee profile, employer info, and company-wide attendance. No overlap.

Naming Consistency4/5

All tools follow the pattern 'timely_<entity>_<info/action>', consistently using underscores and lowercase. Minor abbreviation 'attd' instead of 'attendance' slightly reduces consistency.

Tool Count4/5

With only 4 tools, the server is small but focused on core HR attendance functions. It's slightly below typical range but still appropriate for its narrow scope.

Completeness3/5

Covers essential read operations for employees, attendance, and company info, but lacks any mutation tools (create, update, delete) and other HR features like leave management.

Maintenance

ActivityInactive
ResponsivenessNo issues