npm package: @fedpulse/mcp
Description: Model Context Protocol server for FedPulse — federal contract, exclusion, entity, grant, and wage data for AI agents
Author: FedPulse
Latest version: 1.0.2

# @fedpulse/mcp — FedPulse MCP Server

A Model Context Protocol (MCP) server that exposes the entire FedPulse API surface to AI assistants such as Claude Desktop, Copilot, and any MCP-compatible agent.

Two transports are supported:

| Transport | Use case |
|-----------|----------|
| **Stdio** (`npx @fedpulse/mcp`) | Local Claude Desktop / Cursor integration |
| **HTTP+SSE** (`node src/http-server.js`) | Hosted cloud service at `https://mcp.fedpulse.dev` |

---

## Quick Start — Claude Desktop (stdio)

1. Get your FedPulse API key from [app.fedpulse.dev](https://app.fedpulse.dev).

2. Open `~/Library/Application Support/Claude/claude_desktop_config.json` (macOS) or `%APPDATA%\Claude\claude_desktop_config.json` (Windows) and add:

```json
{
  "mcpServers": {
    "fedpulse": {
      "command": "npx",
      "args": ["@fedpulse/mcp"],
      "env": {
        "FEDPULSE_API_KEY": "fp_live_your_key_here"
      }
    }
  }
}
```

3. Restart Claude Desktop. You will see 14 new tools prefixed `fedpulse`.

---

## Quick Start — HTTP Server (self-hosted or `https://mcp.fedpulse.dev`)

```bash
# Environment variables
export FEDPULSE_API_KEY=fp_live_your_key_here   # passed to the API for each caller
export PORT=3100                                  # default: 3100
export ALLOWED_ORIGINS=https://your-app.com      # optional CORS allowlist (comma-separated)

node src/http-server.js
```

Connect any MCP HTTP client to `http://localhost:3100/mcp` using `Bearer <api_key>` or `X-Api-Key: <api_key>` authentication.

---

## Environment Variables

| Variable | Required | Default | Description |
|----------|----------|---------|-------------|
| `FEDPULSE_API_KEY` | Yes | — | Your FedPulse API key. Passed as the API credential for every request. |
| `FEDPULSE_BASE_URL` | No | `https://api.fedpulse.dev` | Override API base URL (staging, local dev). |
| `FEDPULSE_TIMEOUT_MS` | No | `15000` | Per-request timeout in milliseconds. |
| `PORT` | No | `3100` | HTTP server port (HTTP transport only). |
| `HOST` | No | `0.0.0.0` | HTTP server bind address. |
| `ALLOWED_ORIGINS` | No | `*` | Comma-separated CORS origins for the HTTP server. |

---

## Tools (14 total)

### Opportunities

| Tool | Description |
|------|-------------|
| `search_opportunities` | Full-text + structured search across all federal contract opportunities. Supports NAICS codes, agency, set-aside type, notice type, date ranges, award amounts, and AI-powered fields like categories and keywords. |
| `get_opportunity` | Fetch complete details for a single opportunity by `noticeId`. |
| `get_similar_opportunities` | Find opportunities similar to a given one, matched by NAICS code. |

### Exclusions & Compliance

| Tool | Description |
|------|-------------|
| `check_exclusion` | Check whether a single entity (by UEI, CAGE, or name) appears on the SAM.gov exclusions list. Returns a clear EXCLUDED / NOT EXCLUDED verdict with details. |
| `bulk_compliance_check` | Submit up to 100 entities for exclusion screening in a single call. Returns a per-entity verdict table plus a summary count. |

### Entities

| Tool | Description |
|------|-------------|
| `get_entity_profile` | Full SAM.gov entity profile including registration status, NAICS codes, certifications (8(a), WOSB, SDVOSB, etc.), and contact info. |
| `search_entities` | Search the SAM.gov entity registry by business name, NAICS code, state, certifications, or registration status. |
| `get_entity_contracts` | Award history for a registered entity (by UEI). |

### Intelligence

| Tool | Description |
|------|-------------|
| `get_entity_360` | Cross-dataset 360° profile for an entity: entity record + exclusion status + recent opportunities + market position. |
| `get_market_analysis` | Market intelligence for a NAICS code: award trends, top agencies, top awardees, opportunity pipeline, and competition metrics. |
| `get_agency_profile` | Aggregated contracting profile for a federal agency: NAICS distribution, award count, recent activity, and top categories. |

### Assistance / Grants

| Tool | Description |
|------|-------------|
| `search_grants` | Search federal grant opportunities (Assistance Listings). Supports full-text, agency, assistance type, eligibility, and status filters. |
| `get_grant` | Fetch a grant program by its CFDA program number (e.g., `"10.001"`). |

### Wages

| Tool | Description |
|------|-------------|
| `get_wage_determination` | Look up Service Contract Act (SCA) or Davis-Bacon Act (DBA) wage determinations by state, county, and type. Returns the most recent revision plus all historical revisions. |

---

## Resources (6 URI templates)

Resources can be fetched by MCP-compatible clients using the `fedpulse://` scheme:

| URI Template | Description |
|-------------|-------------|
| `fedpulse://opportunities/{noticeId}` | Single opportunity record (JSON) |
| `fedpulse://entities/{uei}` | Entity registration record (JSON) |
| `fedpulse://exclusions/{exclusionId}` | Exclusion record (JSON) |
| `fedpulse://grants/{programNumber}` | Grant/assistance listing (JSON) |
| `fedpulse://markets/{naics}` | Market analysis for a NAICS code (JSON) |
| `fedpulse://agencies/{departmentSlug}` | Agency contracting profile (JSON), slug is hyphenated department name |

---

## Prompts (3 workflow templates)

Built-in, multi-step LLM workflow prompts that chain multiple tools automatically:

| Prompt | Arguments | Description |
|--------|-----------|-------------|
| `find_opportunities_for_vendor` | `uei`, `limit?` | Full 5-step vendor opportunity discovery: profile check → exclusion check → NAICS-matched search → dedup → ranked shortlist. |
| `compliance_check_before_award` | `uei` | Pre-award due-diligence workflow: SAM status + exclusion active record check + 360° intelligence + structured red-flag report. |
| `market_brief` | `naics`, `context?` | Full market brief generation: market analysis + active opportunity search + optional agency profiles → formatted narrative brief. |

---

## Architecture

```
mcp/
├── bin/
│   └── cli.js                  # Stdio entry point (npx @fedpulse/mcp)
├── src/
│   ├── server.js               # buildMcpServer(client) — wires all tools, resources, prompts
│   ├── http-server.js          # HTTP+SSE transport server
│   ├── client.js               # FedPulseClient — retry, cache-aside, circuit-breaker
│   ├── cache.js                # Zero-dependency LRU cache with TTL
│   ├── errors.js               # Error classes + formatToolError()
│   ├── tools/
│   │   ├── opportunities.js    # search_opportunities, get_opportunity, get_similar_opportunities
│   │   ├── exclusions.js       # check_exclusion, bulk_compliance_check
│   │   ├── entities.js         # get_entity_profile, search_entities, get_entity_contracts
│   │   ├── intelligence.js     # get_entity_360, get_market_analysis, get_agency_profile
│   │   ├── assistance.js       # search_grants, get_grant
│   │   └── wages.js            # get_wage_determination
│   ├── resources/
│   │   └── index.js            # 6 ResourceTemplate registrations
│   └── prompts/
│       └── index.js            # 3 multi-step workflow prompts
└── package.json
```

### Design Decisions

**LRU Cache with domain-aware TTLs**: Results are cached in-process using an O(1) doubly-linked-list LRU to prevent redundant API calls during a session. TTLs are tuned by data volatility (wages: 6h; market analysis: 1h; exclusion checks: 2min; opportunity search: 60s).

**Circuit-breaker on auth failures**: A single confirmed 401 sets `_authFailed = true` on the client, short-circuiting all subsequent calls with an immediate `FedPulseAuthError` — no wasted retries.

**Retry with full-jitter exponential backoff**: Transient 502/503/504 errors and network failures trigger up to 3 retries with `sleep = rand(0, min(cap, base * 2^attempt))` where `base=100ms`, `cap=10s`. Rate-limit 429 retries respect the `Retry-After` response header.

**Per-session server instances (HTTP transport)**: Each HTTP client connection gets its own `FedPulseClient` + `McpServer` pair keyed by `Mcp-Session-Id`. Sessions idle for more than 30 minutes are garbage-collected by a background sweep.

**Stdio isolation**: All diagnostic output (startup messages, errors) goes to `stderr`. `stdout` is reserved exclusively for MCP protocol frames.

---

## Development

```bash
cd mcp
npm install

# Run tests
npm test

# Run stdio server locally
FEDPULSE_API_KEY=fp_test node bin/cli.js

# Run HTTP server locally
FEDPULSE_API_KEY=fp_test node src/http-server.js
```

---

## Security

- API keys are **never logged**. The `FedPulseClient` redacts the key from all error messages.
- HTTP server enforces per-IP sliding-window rate limiting (120 req/min) backed entirely in-process (no Redis dependency at the MCP layer).
- Request bodies are capped at 512 KB.
- CORS origins are restricted to `ALLOWED_ORIGINS` when set.
- The server runs auth validation before any MCP frame is parsed.

---

## Community

- 💬 **[Discord](https://discord.gg/6C74wXN5SE)** — Ask questions, share what you build with AI agents, get help in `#mcp-ai-agents`
- 🔧 [Dashboard](https://app.fedpulse.dev/dashboard) — Manage API keys
- 📖 [MCP Docs](https://app.fedpulse.dev/docs#mcp) — Full MCP documentation
- 🐛 [Bug reports](https://github.com/fedpulse-API/api-issues) — GitHub Issues for the API

---

## License

MIT — See [LICENSE](../LICENSE).