Async MCP Facade Example
This repo accompanies the Medium article on the MCP facade pattern. It ships:
- a JavaScript facade adapter (CLI invoked via
npx) - a Python GraphQL backend (subscriptions for job updates)
- an in-memory job store (demo)
- a simple SSE client example
Components:
- Facade adapter (Node.js + MCP SDK): MCP-facing server that forwards work to the backend and streams progress over Streamable HTTP/SSE using the official MCP SDK.
- Backend (Python GraphQL): Executes the long-running job and publishes updates via subscriptions.
- Example client: Calls the facade and prints SSE progress + final MCP response.
Flow:
- Client calls
/mcpon the facade. - Facade starts a backend GraphQL job (mutation).
- Backend emits updates on a GraphQL subscription.
- Facade relays updates as MCP notifications over SSE.
- Facade returns final MCP response when complete.
Ports:
- Backend GraphQL:
http://127.0.0.1:5000/graphql - Facade adapter:
http://127.0.0.1:7000
- Start the backend
GRAPHQL_API_TOKEN=dev-token docker compose up --build
If you omit GRAPHQL_API_TOKEN, Compose defaults it to dev-token (see docker-compose.yml).
- Install Node dependencies
npm install
- Start the facade adapter
node bin/mcp-facade.js http://127.0.0.1:5000/graphql --listen 7000 --header "Authorization: Bearer dev-token"
To pass auth to the backend GraphQL service:
node bin/mcp-facade.js http://127.0.0.1:5000/graphql --header "Authorization: Bearer YOUR_TOKEN"
When using Compose defaults, the token is dev-token.
- Run the example client
node client/facade_client.js http://127.0.0.1:7000
The facade exposes one MCP tool named long_running_task. Example prompts:
- "Run the long_running_task with input: demo"
- "Start a long-running job and stream progress"
- "Use long_running_task to process: hello world"
long_running_task- Description: Start a simulated long-running job and stream progress updates (demo/test).
- Input:
{ "input": "string" }
{
"mcpServers": {
"myMcp": {
"command": "npx",
"args": [
"-y",
"github:richtobey/async-mcp-server",
"http://127.0.0.1:5000/graphql",
"--stdio",
"--header",
"Authorization: Bearer dev-token"
]
}
}
}- Clone the repo locally.
- Start the backend:
docker compose up -d backend- (or run the full demo with
make demo)
- In Cursor, open Settings -> MCP and add the config block above.
- Ensure the backend is reachable at
http://127.0.0.1:5000/graphql.
Notes:
npx github:richtobey/async-mcp-serverruns theasync-mcp-serverbin from this repo.- The facade uses stdio mode by default when
--listenis omitted (ideal for Cursor).--stdioforces stdio. - The repo must be public for
npxto fetch it.
docs/architecture.mddocs/api.mddocs/design.mddocs/ops.md
npm test
Run the whole flow (backend + facade + client):
scripts/run-demo.sh
If you prefer make:
make
make demo
make backend
make test
make diagrams
fetch failedor connection refused: ensure the backend is running (docker compose up --build) and that the facade points tohttp://127.0.0.1:5000/graphql.- Port already in use: stop the existing process or choose a new port via
--listen. - No progress events: confirm the backend is reachable and the GraphQL subscription is accepted.
- Unauthorized errors: if
GRAPHQL_API_TOKENis set, passAuthorization: Bearer <token>via--header. - Unauthorized on WebSocket subscription: ensure the same token is used for both HTTP and WS; the facade forwards auth to the subscription via
connectionParamsand a query param.
See CONTRIBUTING.md for setup and guidelines.
See CODE_OF_CONDUCT.md.
See SECURITY.md.
See CHANGELOG.md.
MIT. See LICENSE.
