Skip to main content
Glama
Koslovski79

platform-adapter-mcp

by Koslovski79
README.md
# platform-adapter-mcp

A reference implementation of the **adapter pattern for the Model Context
Protocol (MCP)** — the same architecture Claude Code uses internally to
expose tools to its agent loop.

The reference wraps seven real-world REST/GraphQL APIs (HackerOne,
Intigriti, Bugcrowd, Code4rena, Immunefi, YesWeHack, HackenProof) behind
a single, uniform tool surface. Swap the adapters for CRMs, ATSs,
finance APIs, internal services — the MCP layer doesn't change.

```
+---------------------------------+
|   Claude Code / LLM agent       |  ← makes tool calls
+---------------------------------+
              |  MCP (JSON-RPC)
+---------------------------------+
|   FastMCP server (server.py)    |  ← uniform tool surface
+---------------------------------+
              |
+---------------------------------+
|   Adapter registry (lazy)       |  ← one class per upstream API
+---------------------------------+
              |
+------+------+------+------+-----+
|  H1 | Bug  |  C4  | ... |  CRM |  ← platform-specific auth, rate limit,
+------+------+------+------+-----+     schema normalization
```

## What this demonstrates

- **Adapter pattern in Python.** One abstract base class
  (`adapters/base.py`) with `authenticate`, `list_programs`, `get_program`,
  `get_scope`. Every platform implements the same four methods against a
  different upstream schema.
- **Lazy initialization.** Adapters only spin up when first called and
  only if credentials are configured — same pattern you'd use for an
  MCP server that conditionally exposes Salesforce vs. HubSpot based on
  which credentials exist in the environment.
- **Schema normalization.** Each platform returns data in a different
  shape (HackerOne: REST + GraphQL; Bugcrowd: GraphQL microservice;
  Code4rena: undocumented JSON; Immunefi: REST with quirky auth). They
  all map to the same `Program` / `ScopeAsset` / `Brief` dataclasses
  consumed by the MCP tools.
- **Prompt-driven tool design.** Each `@mcp.tool()` exposes a single
  high-level intent (`cross_platform_scope("shopify.com")`) rather than
  raw CRUD primitives — this is how you keep tool descriptions short and
  agent-friendly.

## Why this matters for prompt-driven development

MCP is the standard tool protocol for Claude Code and most modern agent
runtimes. Writing a thin MCP wrapper around any existing API turns that
API into a callable tool the agent can use on its own. The same pattern
works for:

- **CRMs** (Salesforce, HubSpot, Pipedrive)
- **ATSs** (Greenhouse, Lever, Workable)
- **Internal services** (any authenticated REST API in your stack)
- **Finance/payment tools** (Stripe, Mercury, Plaid)

The agent never needs to know the upstream API exists. It calls
`find_account(domain="acme.com")` and the adapter handles auth, retry,
and schema mapping.

## Quick start

```bash
git clone https://github.com/Koslovski79/platform-adapter-mcp
cd platform-adapter-mcp
pip install -r requirements.txt

cp config.example.yaml config.yaml
# edit config.yaml with your platform credentials

python server.py
```

Then add to your MCP client (Claude Desktop, etc.):

```json
{
  "mcpServers": {
    "platforms": {
      "command": "python",
      "args": ["/path/to/platform-adapter-mcp/server.py"],
      "env": {"BB_CONFIG": "/path/to/platform-adapter-mcp/config.yaml"}
    }
  }
}
```

The six `@mcp.tool()` functions become available immediately.

## Layout

```
platform-adapter-mcp/
├── server.py              # FastMCP server, 6 tools, lazy adapter registry
├── config.example.yaml    # Platform credentials (copy to config.yaml)
├── adapters/
│   ├── base.py            # Abstract adapter + Program/ScopeAsset/Brief models
│   ├── hackerone.py       # H1 REST + GraphQL adapter (full)
│   ├── intigriti.py       # Intigriti REST adapter (full)
│   ├── bugcrowd.py        # Bugcrowd GraphQL adapter (full)
│   ├── code4rena.py       # Code4rena REST adapter (full)
│   ├── immunefi.py        # Immunefi REST adapter (full)
│   ├── yeswehack.py       # YesWeHack REST adapter (stub)
│   └── stubs.py           # Sherlock + HackenProof placeholder adapters
└── requirements.txt
```

## Adding a new platform

1. Create `adapters/newplatform.py` extending `BaseAdapter`.
2. Implement `authenticate()`, `list_programs()`, `get_program()`,
   `get_scope()`.
3. Register the class in `ADAPTER_CLASSES` in `server.py`.
4. Add a config block in `config.yaml`.
5. Done — the agent can now call the platform through the same six tools.

The same five steps add a new CRM, a new ATS, a new payment provider, or
a new internal microservice.

## Notes

- No credentials ship in this repo. `config.example.yaml` shows the
  structure; users copy it to `config.yaml` and fill in their own keys.
- Adapters only activate when `enabled: true` AND valid credentials are
  present. The server logs which adapters come online at startup.
- The `raw` field on every returned model preserves the original API
  response, so agents can reach past the normalized model when needed
  without changing the adapter.