Skip to main content
Glama
README.md
# Backwork MCP Server

Official Model Context Protocol (MCP) server for the [Backwork API](https://backworkhealth.com). It gives AI assistants controlled access to Medicare coverage policies, medical code intelligence, prior authorization checks, claim validation, compliance review, drug formulary evidence, and webhook operations.

## Current Setup

For Claude Code, use the hosted Streamable HTTP MCP endpoint with OAuth. This does not require copying a Backwork API key into Claude Code:

```bash
claude mcp remove backwork 2>/dev/null || true
claude mcp add --transport http --scope user backwork https://backworkhealth.com/mcp
```

Then start Claude Code, run `/mcp`, select `backwork`, complete the browser login, and approve the Backwork consent screen.

Codex currently uses the local stdio server with a Backwork API key:

```bash
export BACKWORK_API_KEY=bwk_live_YOUR_API_KEY
codex mcp add backwork --env BACKWORK_API_KEY=$BACKWORK_API_KEY -- npx -y @backwork/mcp
```

Use the local stdio setup when your MCP client does not support remote Streamable HTTP yet, or when you want to run the server entirely on your machine.

## Codex

Use local stdio with a Backwork API key:

```bash
export BACKWORK_API_KEY=bwk_live_YOUR_API_KEY
codex mcp add backwork --env BACKWORK_API_KEY=$BACKWORK_API_KEY -- npx -y @backwork/mcp
```

The hosted Backwork MCP endpoint requires OAuth. Do not use a Backwork API key as a bearer token against `https://backworkhealth.com/mcp`. If you operate a private self-hosted HTTP server in API-key or dual-auth mode, Codex can connect to that private URL with `--bearer-token-env-var`.

## Claude Code

For hosted Streamable HTTP, use OAuth:

```bash
claude mcp remove backwork 2>/dev/null || true
claude mcp add --transport http --scope user backwork https://backworkhealth.com/mcp
```

Then run `claude`, open `/mcp`, and authenticate `backwork`. Claude Code discovers the OAuth protected-resource metadata, opens your browser, sends you through Backwork login, and stores the OAuth token after you approve the consent screen.

Verify the server is configured:

```bash
claude mcp list
claude mcp get backwork
```

If OAuth discovery needs to be pinned explicitly, add the same server as JSON:

```bash
claude mcp remove backwork 2>/dev/null || true
claude mcp add-json backwork '{
  "type": "http",
  "url": "https://backworkhealth.com/mcp",
  "oauth": {
    "scopes": "backwork:mcp read"
  }
}'
```

For older clients that cannot complete remote OAuth, use local stdio:

```bash
export BACKWORK_API_KEY=bwk_live_YOUR_API_KEY
claude mcp add backwork -e BACKWORK_API_KEY=$BACKWORK_API_KEY -- npx -y @backwork/mcp
```

## Cursor, VS Code, Windsurf, and Other MCP Clients

For clients that only support stdio commands:

```json
{
  "mcpServers": {
    "backwork": {
      "command": "npx",
      "args": ["-y", "@backwork/mcp"],
      "env": {
        "BACKWORK_API_KEY": "bwk_live_YOUR_API_KEY"
      }
    }
  }
}
```

The hosted Backwork MCP endpoint requires OAuth. For clients that support only remote URLs and static headers, deploy a private self-hosted server in API-key or dual-auth mode and set the bearer header using the client's documented secret mechanism. If the client only accepts static JSON, replace the placeholder directly:

```json
{
  "mcpServers": {
    "backwork": {
      "url": "https://your-private-mcp.example.com/mcp",
      "headers": {
        "Authorization": "Bearer bwk_live_YOUR_API_KEY"
      }
    }
  }
}
```

## Self-Hosting

Run a Streamable HTTP server:

```bash
git clone https://github.com/tylergibbs1/backwork-mcp.git
cd backwork-mcp
npm install
npm run build
npm run start:http
```

Defaults:

| Setting | Default | Override |
| --- | --- | --- |
| Transport | `stdio` | `--http` or `BACKWORK_MCP_TRANSPORT=http` |
| Host | `127.0.0.1` | `--host` or `BACKWORK_MCP_HOST` |
| Port | `3000` | `--port` or `BACKWORK_MCP_PORT` or `PORT` |
| MCP path | `/mcp` | `--path` or `BACKWORK_MCP_PATH` |
| Allowed hosts | loopback/private hosts, `VERCEL_URL`, or configured public host | `BACKWORK_MCP_ALLOWED_HOSTS` or `BACKWORK_MCP_PUBLIC_HOST` |

HTTP mode requires `Authorization: Bearer` per request. By default this bearer is a Backwork API key. For hosted remote MCP deployments, enable OAuth protected-resource discovery so Claude-compatible clients can authenticate users through your authorization server:

```bash
BACKWORK_MCP_AUTH_MODE=oauth \
BACKWORK_MCP_OAUTH_AUTHORIZATION_SERVERS=https://backworkhealth.com \
BACKWORK_MCP_OAUTH_SCOPES="backwork:mcp read" \
npm run start:http
```

The server publishes OAuth Protected Resource Metadata at `/.well-known/oauth-protected-resource` and includes that URL in `WWW-Authenticate` challenges. If your Backwork API accepts OAuth access tokens directly, no extra mapping is needed; the MCP server forwards the OAuth bearer downstream. If your authorization server exposes a Backwork API key in token introspection, set `BACKWORK_MCP_OAUTH_INTROSPECTION_URL` and `BACKWORK_MCP_OAUTH_API_KEY_CLAIM` to validate the access token and map it to the downstream Backwork credential.

For a private single-tenant deployment where the server environment supplies the key, set:

```bash
BACKWORK_MCP_ALLOW_ENV_KEY=true BACKWORK_API_KEY=bwk_live_YOUR_API_KEY npm run start:http
```

Only use `BACKWORK_MCP_ALLOW_ENV_KEY=true` on loopback or private-network deployments protected by network access control. Public deployments should require a bearer token per request, set `BACKWORK_MCP_ALLOWED_HOSTS`/`BACKWORK_MCP_PUBLIC_HOST`, and set `BACKWORK_MCP_ALLOWED_ORIGINS` only to exact browser origins that may connect.

### Vercel Hosting

This repo can deploy as an API-only Vercel project. The production project uses:

```bash
BACKWORK_MCP_AUTH_MODE=oauth
BACKWORK_MCP_PUBLIC_HOST=backworkhealth.com
BACKWORK_MCP_PUBLIC_URL=https://backworkhealth.com
BACKWORK_MCP_ALLOWED_HOSTS=backworkhealth.com,mcp.backworkhealth.com,backwork-mcp.vercel.app
BACKWORK_MCP_OAUTH_AUTHORIZATION_SERVERS=https://backworkhealth.com
BACKWORK_MCP_OAUTH_RESOURCE=https://backworkhealth.com/mcp
BACKWORK_MCP_OAUTH_SCOPES="backwork:mcp read"
BACKWORK_MCP_OAUTH_REQUIRED_SCOPES=backwork:mcp
BACKWORK_MCP_OAUTH_INTROSPECTION_URL=https://backworkhealth.com/api/oauth/introspect
BACKWORK_MCP_OAUTH_EXPECTED_AUDIENCE=https://backworkhealth.com/mcp
```

The Vercel functions expose:

| Path | Purpose |
| --- | --- |
| `/mcp` | Streamable HTTP MCP endpoint |
| `/health` | Lightweight MCP server health check |
| `/.well-known/oauth-protected-resource` | OAuth protected-resource metadata when OAuth is configured |
| `/` | Basic endpoint metadata |

The Backwork web app that issues OAuth tokens must also be configured:

```bash
BACKWORK_OAUTH_ISSUER=https://backworkhealth.com
BACKWORK_OAUTH_SIGNING_SECRET=<generate with: openssl rand -base64 48>
BACKWORK_MCP_RESOURCE=https://backworkhealth.com/mcp
```

Production OAuth discovery fails closed unless `BACKWORK_OAUTH_SIGNING_SECRET` is at least 32 characters and Redis or Vercel KV is configured for one-time consent and authorization-code storage.

Health check:

```bash
curl http://localhost:3000/health
```

## Local Development

```bash
npm install
npm run build
BACKWORK_API_KEY=bwk_live_YOUR_API_KEY npm start
```

Useful commands:

```bash
npm run start:http
node build/src/index.js --help
```

Requires Node.js 18 or newer.

## Available Tools

Tool names use the `backwork_` prefix for discoverability when this server is installed alongside other MCP servers. The default surface is intentionally workflow-level rather than a 1:1 API wrapper, so agents see fewer choices and common tasks require fewer tool calls.

All tools include `title`, `description`, `inputSchema`, `outputSchema`, and MCP annotations. Successful calls return readable text plus `structuredContent` with `message`, and when available, raw Backwork API `data` and `meta`. Tool-level failures return `isError: true`. For tools that combine read and write actions, annotations are conservative at the tool level.

| Primary tool | Purpose |
| --- | --- |
| `backwork_coverage_lookup` | Look up procedure codes and combine code details, policy evidence, prior authorization, claim risk, jurisdiction comparison, and spending evidence |
| `backwork_policy_research` | Search policies, fetch one policy, search extracted criteria, review policy changes, or map MAC jurisdictions |
| `backwork_claim_validation` | Validate claim coverage, documentation requirements, denial risk, and optional policy-specific criteria |
| `backwork_prior_auth_research` | Check Medicare prior authorization, start payer website research, or poll an async research task |
| `backwork_drug_formulary_research` | Search commercial pharmacy-benefit evidence from CVS Caremark, Express Scripts, and UnitedHealthcare / Optum Rx |
| `backwork_compliance_review` | Review compliance stats, list unreviewed policy changes, or acknowledge changes |
| `backwork_webhook_management` | List, create, update, delete, or test webhook endpoints |
| `backwork_system_health` | Check Backwork API health and dependency status |

### Response Format

Every tool accepts:

```json
{
  "response_format": "markdown"
}
```

Use `"markdown"` for readable output or `"json"` to make the text content mirror the returned `structuredContent`.

## Example Prompts

```text
Is CPT 76942 covered in Texas, and does it require prior authorization?
```

```text
Compare coverage for J0585 across JM and JH.
```

```text
Validate denial risk for 99213 with diagnosis E11.9 for Medicare in Texas.
```

```text
Search formulary evidence for Ozempic across commercial PBMs.
```

## Testing and Evaluations

Run the build and MCP metadata smoke test:

```bash
npm test
```

The smoke test starts the built stdio server with a dummy key, verifies the 8 workflow tools, checks titles, schemas, annotations, output schemas, `response_format`, and verifies local validation failures are reported with `isError: true`.

The `evals/` directory includes a tool-discoverability evaluation and a read-only data evaluation built from fixed source-backed policy/code records. Refresh the read-only answers intentionally when Backwork source data is updated.

## Release

The package publishes to npm as `@backwork/mcp`.

The npm package is available under the Backwork scope as `@backwork/mcp`.

1. Configure npm Trusted Publishing for `tylergibbs1/backwork-mcp`, workflow `release.yml`, environment `npm`, package `@backwork/mcp`.
2. Update `package.json` and `package-lock.json` to the new version.
3. Push a matching tag, for example `v2.0.0`.
4. The release workflow installs with `npm ci`, runs the build/smoke test, verifies `npm pack --dry-run`, and publishes with npm provenance.

## Environment Variables

| Variable | Required | Description |
| --- | --- | --- |
| `BACKWORK_API_KEY` | Stdio yes; HTTP no | Backwork API key. In HTTP mode, prefer `Authorization: Bearer` per request. |
| `BACKWORK_API_BASE` | No | Override the API base URL. |
| `BACKWORK_MCP_TRANSPORT` | No | `stdio` or `http`. |
| `BACKWORK_MCP_HOST` | No | HTTP bind host. Defaults to `127.0.0.1`. |
| `BACKWORK_MCP_PORT` | No | HTTP bind port. |
| `BACKWORK_MCP_PATH` | No | HTTP MCP path. |
| `BACKWORK_MCP_ALLOWED_ORIGINS` | No | Comma-separated allowed HTTP origins. Loopback origins are allowed for loopback requests. |
| `BACKWORK_MCP_ALLOW_ORIGIN` | No | Backward-compatible alias for `BACKWORK_MCP_ALLOWED_ORIGINS`. |
| `BACKWORK_MCP_ALLOWED_HOSTS` | No | Comma-separated allowed HTTP Host headers for public deployments. |
| `BACKWORK_MCP_ALLOW_HOST` | No | Backward-compatible alias for `BACKWORK_MCP_ALLOWED_HOSTS`. |
| `BACKWORK_MCP_PUBLIC_HOST` | No | Primary public host allowed for HTTP requests. |
| `BACKWORK_MCP_PUBLIC_URL` | No | Canonical public origin for OAuth metadata, e.g. `https://backworkhealth.com`. |
| `BACKWORK_MCP_ALLOW_ENV_KEY` | No | Allow private HTTP requests without bearer auth to use `BACKWORK_API_KEY`. |
| `BACKWORK_MCP_AUTH_MODE` | No | HTTP bearer mode: `api-key`, `oauth`, or `dual`. Defaults to `dual` when OAuth authorization servers are configured, otherwise `api-key`. |
| `BACKWORK_MCP_OAUTH_AUTHORIZATION_SERVERS` | OAuth | Comma-separated OAuth issuer / authorization server URLs advertised in protected-resource metadata. |
| `BACKWORK_MCP_OAUTH_RESOURCE` | No | Override the RFC 8707 resource identifier. Defaults to the public MCP URL. |
| `BACKWORK_MCP_OAUTH_SCOPES` | No | Space- or comma-separated scopes advertised to clients. Defaults to `backwork:mcp`. |
| `BACKWORK_MCP_OAUTH_REQUIRED_SCOPES` | No | Space- or comma-separated scopes required after token introspection. |
| `BACKWORK_MCP_OAUTH_INTROSPECTION_URL` | No | RFC 7662 token introspection endpoint used to validate OAuth access tokens. |
| `BACKWORK_MCP_OAUTH_INTROSPECTION_CLIENT_ID` | No | Client ID for introspection basic auth. |
| `BACKWORK_MCP_OAUTH_INTROSPECTION_CLIENT_SECRET` | No | Client secret for introspection basic auth. |
| `BACKWORK_MCP_OAUTH_INTROSPECTION_TOKEN` | No | Bearer token for introspection when basic auth is not used. |
| `BACKWORK_MCP_OAUTH_API_KEY_CLAIM` | No | Dot-path claim from introspection response to use as the downstream Backwork credential. If omitted, the OAuth access token is forwarded. |
| `BACKWORK_MCP_OAUTH_EXPECTED_AUDIENCE` | No | Comma-separated allowed `aud` values when introspection responses include an audience. |

## Troubleshooting

### Missing API Key

For stdio, set `BACKWORK_API_KEY` in the MCP client configuration. For HTTP API-key mode, send `Authorization: Bearer <key>`. For HTTP OAuth mode, configure `BACKWORK_MCP_OAUTH_AUTHORIZATION_SERVERS` and send `Authorization: Bearer <access_token>`.

### 401 From HTTP MCP

The remote server did not receive a bearer token. Configure your MCP client to authenticate with OAuth or send an `Authorization` header. OAuth-enabled deployments include `resource_metadata` in the `WWW-Authenticate` header to point clients at `/.well-known/oauth-protected-resource`.

### Claude Code OAuth

If Claude Code does not open the browser, run `/mcp`, select `backwork`, and choose the authenticate action. If it gives you a URL instead of opening a browser, copy that URL into your browser.

If the browser redirect back to Claude Code fails after consent, copy the full callback URL from the browser address bar and paste it into the Claude Code prompt.

If Claude Code keeps using an old token, open `/mcp`, select `backwork`, clear authentication, then authenticate again. You can also remove and re-add the server with:

```bash
claude mcp remove backwork
claude mcp add --transport http --scope user backwork https://backworkhealth.com/mcp
```

If discovery returns `503`, the Backwork web app is intentionally refusing to advertise OAuth because production signing or Redis/KV state storage is missing.

If tool calls authenticate but fail with `invalid_token` or `invalid_target`, check that `BACKWORK_MCP_RESOURCE`, `BACKWORK_MCP_OAUTH_RESOURCE`, and `BACKWORK_MCP_OAUTH_EXPECTED_AUDIENCE` all use:

```text
https://backworkhealth.com/mcp
```

### Rate Limits

Wait for the reset window or use a higher-capacity API plan.

## Support

- Documentation: https://backworkhealth.com/docs
- Issues: https://github.com/tylergibbs1/backwork-mcp/issues
- Email: support@backworkhealth.com

## License

MIT

TDQS

A4/5.0

Scored across 8 tools

Disambiguation5/5

Each tool has a clearly distinct purpose within the Medicare coverage domain. For example, check_prior_auth focuses on authorization requirements, compare_policies on regional differences, get_policy on detailed policy information, and search_policies on policy discovery, with no significant overlap in functionality. The descriptions clearly differentiate their roles, making it easy for an agent to select the right tool.

Naming Consistency5/5

All tool names follow a consistent verb_noun pattern using snake_case, such as check_prior_auth, compare_policies, get_policy, and search_policies. This uniformity enhances readability and predictability, allowing agents to easily understand and navigate the toolset without confusion from mixed naming conventions.

Tool Count5/5

With 8 tools, this server is well-scoped for its purpose of Medicare coverage and policy management. Each tool serves a specific, necessary function, from checking prior authorizations to searching policies and comparing jurisdictions, providing comprehensive coverage without being overly sparse or bloated. The count aligns perfectly with the domain's complexity.

Completeness5/5

The toolset offers complete coverage for Medicare policy workflows, including discovery (search_policies, lookup_code), detailed retrieval (get_policy, get_policy_changes), comparison (compare_policies), jurisdiction handling (list_jurisdictions), and specific checks (check_prior_auth, search_criteria). There are no obvious gaps; agents can perform end-to-end tasks from code lookup to authorization assessment.

Maintenance

ActivityMaintained
ResponsivenessNo issues