Fake Pennylane MCP Server
by leyriel
README.md
# Fake Pennylane MCP Server
An open-source fake server that emulates the Pennylane MCP experience for local development, automated tests, demos, and CI pipelines — without requiring a real Pennylane account or real accounting data.
> Status: working early implementation. The repository now includes a runnable Streamable HTTP MCP server, deterministic fixtures, scenario packs, static bearer auth, and a fake OAuth flow for callback/integration testing.
## Why this project exists
Pennylane MCP is useful, but it is hard to validate an integration when you do not have:
- a real Pennylane account,
- a portfolio of test companies and customers,
- deterministic accounting fixtures,
- a safe environment for demos and CI.
This project solves that gap by providing a predictable, developer-friendly test double for a Pennylane-like MCP server.
## Current capabilities
The current implementation provides:
- a **Streamable HTTP MCP server**,
- deterministic fixture loading from JSON,
- scenario-pack selection,
- optional **static bearer token** authentication,
- a **fake OAuth authorization-code flow** for end-to-end callback testing,
- automated local tests for runtime, scenarios, and auth.
### Exposed tools
- `get_context`
- `get_company`
- `list_companies`
- `list_customers`
- `get_customer`
- `list_customer_invoices`
## Quickstart
### Requirements
- Python 3.11+
- `uv`
### Install dependencies
```bash
cd /home/leyriel/dev/fake-pennylane-mcp-server
uv sync
```
### Run the server
Default fixture dataset, no auth:
```bash
uv run python -m fake_pennylane_mcp_server --host 127.0.0.1 --port 8000
```
With a scenario pack:
```bash
uv run python -m fake_pennylane_mcp_server \
--host 127.0.0.1 \
--port 8000 \
--scenario unpaid_invoice
```
With static bearer auth:
```bash
uv run python -m fake_pennylane_mcp_server \
--host 127.0.0.1 \
--port 8000 \
--auth-mode static_bearer \
--bearer-token test-secret-token
```
With fake OAuth flow:
```bash
uv run python -m fake_pennylane_mcp_server \
--host 127.0.0.1 \
--port 8000 \
--auth-mode fake_oauth
```
## Run with Docker Compose
Build and start the default server:
```bash
docker compose up --build
```
Run detached:
```bash
docker compose up --build -d
```
Stop it:
```bash
docker compose down
```
Compose now defaults to a more exotic host port (`18080`) to avoid common collisions. If you still need a different host port, override it explicitly:
```bash
PUBLISHED_PORT=28080 docker compose up --build -d
```
Use a scenario pack:
```bash
SCENARIO_NAME=unpaid_invoice docker compose up --build
```
Use static bearer auth:
```bash
AUTH_MODE=static_bearer BEARER_TOKEN=test-secret-token docker compose up --build
```
Compose now defaults to `AUTH_MODE=fake_oauth` for easier browser-based local integration tests. To switch explicitly:
```bash
AUTH_MODE=fake_oauth docker compose up --build
```
By default Compose exposes the server on `http://127.0.0.1:${PUBLISHED_PORT:-18080}/mcp`, publishes OAuth metadata on the same host port, and mounts `./fixtures` read-only into the container.
## Scenario packs
The default fixture file currently exposes these scenario packs:
- `default`
- `customer_found`
- `customer_not_found`
- `unpaid_invoice`
- `multi_company`
Each scenario narrows the deterministic dataset to a stable business situation.
## Authentication modes
### `none`
No Authorization header is required.
### `static_bearer`
Requires a bearer token on MCP HTTP requests.
Example header:
```text
Authorization: Bearer ***
```
### `fake_oauth`
Exposes a minimal fake OAuth authorization server alongside the MCP resource server.
Included endpoints:
- `/.well-known/oauth-authorization-server`
- `/.well-known/oauth-protected-resource/mcp`
- `/authorize`
- `/token`
Current fake client contract:
- `client_id`: `fake-public-client`
- token endpoint auth method: `none`
- redirect URIs:
- `http://127.0.0.1:9999/callback`
- `http://localhost:9999/callback`
- `http://127.0.0.1:3800/api/settings/pennylane/callback`
- `http://localhost:3800/api/settings/pennylane/callback`
- scope: `mcp:access`
Useful Compose defaults for MissionGuard local OAuth validation:
- `AUTH_MODE=fake_oauth`
- `ISSUER_URL=http://127.0.0.1:${PUBLISHED_PORT:-18080}`
- `RESOURCE_SERVER_URL=http://127.0.0.1:${PUBLISHED_PORT:-18080}/mcp`
This flow is meant for local integration tests and fake callback simulations — not as a production OAuth server.
## Compatibility and status tracking
See:
- `docs/compatibility-matrix.md`
- `docs/README.md`
## Example clients
See:
- `examples/basic_client.py`
- `examples/bearer_client.py`
- `examples/README.md`
## Running tests
```bash
uv run pytest -q
```
## Development workflow
Typical local loop:
1. update fixtures / scenarios / auth behavior,
2. run `uv run pytest -q`,
3. run one of the example clients against a local server,
4. commit the change.
## Project structure
```text
.
├── docs/
├── examples/
├── fixtures/
├── src/
├── tests/
├── CONTRIBUTING.md
├── Dockerfile
├── docker-compose.yml
├── LICENSE
├── README.md
└── pyproject.toml
```
## Roadmap
### Bootstrap
- [x] Create Plane project
- [x] Create public GitHub repository
- [x] Publish initial detailed README
- [x] Prepare repo structure for implementation handoff
### Implementation milestones
- [x] Implement fake Streamable HTTP MCP runtime
- [x] Add deterministic fixture loading
- [x] Add fake customer / invoice queries
- [x] Add scenario packs
- [x] Add auth modes for integration testing
- [x] Add runnable example clients
- [x] Add fake OAuth flow for end-to-end callback testing
- [x] Publish a compatibility matrix
- [x] Add Docker and Docker Compose local runtime
### Next useful milestones
- [ ] add GitHub Actions CI once a token with `workflow` scope is available
- [ ] enrich compatibility with more Pennylane-like tools
- [ ] add more domain fixture packs
- [ ] add standalone OAuth example client
- [ ] document additional integration recipes
## Open-source direction
The intent is for this project to be genuinely useful to a broader audience, not just a one-off internal spike.
That means we optimize for:
- clarity of documentation,
- ease of local setup,
- stable deterministic fixtures,
- transparent scope,
- simple contribution paths.
## Project origin
This repository was spun out from work around a MissionGuard integration effort, where a Pennylane MCP replacement strategy needed a realistic test environment without depending on a real Pennylane tenant.
## License
MIT.
## Disclaimer
This project is **not affiliated with or endorsed by Pennylane**.
It is an independent open-source testing utility intended to emulate part of a Pennylane-like MCP integration surface for development and testing purposes only.
This server cannot be deployed
Maintenance
ActivitySlowing
ResponsivenessNo issues