Skip to main content
Glama
amoljagtap17

users

by amoljagtap17
README.md
# typescript-mcp-server

MCP servers for the Portfolio API, served over HTTP by one Express app.

| Endpoint             | Server             | Tools                                   |
| -------------------- | ------------------ | --------------------------------------- |
| `/users/mcp`         | `users-mcp`        | `get_user_by_email`, `get_user_by_name` |
| `/accounts/mcp`      | `accounts-mcp`     | `get_accounts_by_user_id`               |
| `/transactions/mcp`  | `transactions-mcp` | `get_transactions_by_account_id`        |

The tools chain: an email resolves to a user id, which resolves to accounts,
whose ids resolve to transactions.

Default port: `4000`. VS Code is wired to both in [.vscode/mcp.json](.vscode/mcp.json).

## Scripts

| Command             | Purpose                             |
| ------------------- | ----------------------------------- |
| `npm run dev`       | Run from source with `tsx`          |
| `npm run build`     | Compile to `dist/`                  |
| `npm start`         | Run the compiled build              |
| `npm run typecheck` | Type-check without emitting         |

## Configuration

Copy `.env.example` to `.env`. All variables are declared and validated in
[src/config.ts](src/config.ts); startup fails with a readable message if any
are invalid.

| Variable             | Default                 | Purpose                                |
| -------------------- | ----------------------- | -------------------------------------- |
| `NODE_ENV`           | `development`           | `development` enables pretty logs       |
| `LOG_LEVEL`          | `info`                  | `debug`/`info`/`warn`/`error`/`silent` |
| `PORTFOLIO_API_BASE` | `http://localhost:3000` | Base URL of the Portfolio API          |

## Layout

```
src/
  index.ts               Mounts every MCP server on the Express app
  config.ts              Env vars, loaded and validated once
  logger.ts              pino logger (pretty in development)
  api.ts                 Shared axios client for the Portfolio API
  tool-result.ts         Builds the CallToolResult shape
  servers/
    users/
      index.ts           createUsersServer(): registers the tools
      users.api.ts       API calls that return data
      users.schema.ts    zod schemas for input and output
    accounts/
      index.ts           createAccountsServer()
      accounts.api.ts
      accounts.schema.ts
    transactions/
      index.ts           createTransactionsServer()
      transactions.api.ts
      transactions.schema.ts
```

### Logging

Use the `logger` from [src/logger.ts](src/logger.ts), which writes to stderr.
Avoid `console.log`: it writes to stdout, which is the JSON-RPC wire if this
project is ever switched back to the stdio transport.

### Errors

Tool handlers do not need `try`/`catch`. The MCP SDK catches anything thrown
and returns it as a tool result flagged `isError`, so an API call can simply
throw when there is no match.

### Schemas

`outputSchema` is enforced: the SDK validates `structuredContent` against it
and fails the call on a mismatch — but it discards the parsed value, so any
normalising has to happen in the `.api.ts` file before the data is returned.

json-server returns each primary key as a **string** (`"id": "1"`) while
leaving foreign keys **numeric** (`"userId": 1`). The schemas use
`z.coerce.number()` on ids to smooth that over; they still advertise a plain
integer. Check a new endpoint with `curl` rather than trusting `db.json` —
json-server rewrites the ids it loads from there.

## Adding a tool

Add the API call to `<server>.api.ts`, its schemas to `<server>.schema.ts`, and
a `server.registerTool(...)` block in that server's `index.ts`.

## Adding another MCP server

Create `src/servers/<name>/` with the same three files, exporting a
`create<Name>Server(): McpServer`, then add one line to the `MCP_SERVERS` array
in [src/index.ts](src/index.ts).

TDQS

A3.7/5.0

Scored across 2 tools

Disambiguation5/5

The two tools are clearly distinguished by their lookup parameter: email vs. name. Descriptions explicitly state each input, so an agent can confidently select the appropriate tool without ambiguity.

Naming Consistency5/5

Both tools follow the same verb_noun_by_attribute pattern (get_user_by_...). This is consistent and predictable, making it easy to infer behavior from the name.

Tool Count3/5

With only 2 tools, the server feels thin, but the scope may be intentionally limited to user lookup. It is not as extreme as having a single trivial tool, so it sits at the borderline.

Completeness2/5

The server only provides read operations for users. There are no create, update, delete, or list endpoints, which are essential for a 'users' domain. This is a significant functional gap that will hinder agents needing full user lifecycle management.

Maintenance

ActivitySlowing
ResponsivenessNo issues