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.This server cannot be deployed
Maintenance
ActivityInactive
ResponsivenessNo issues