A Rust-based Model Context Protocol (MCP) server that automatically exposes OpenAPI/Swagger endpoints as MCP tools.
This server bridges OpenAPI specifications with the Model Context Protocol, allowing AI assistants to interact with REST APIs through standardized MCP tools. It supports multiple operation modes and includes OAuth2 authentication capabilities.
- Parse OpenAPI 3.0 specifications (JSON/YAML)
- Generate MCP tools from API endpoints
- Multiple server modes: STDIO, HTTP, SSE
- Route filtering and description customization
- OAuth2 authentication support (GitHub, Google, Microsoft, Generic)
- Docker support with Keycloak integration
cargo build --releaseThe binary will be available at target/release/yas-mcp
docker compose upyas-mcp --swagger-file path/to/openapi.yaml --mode stdioCreate a config.yaml:
server:
mode: stdio
host: 127.0.0.1
port: 3000
name: yas-mcp
version: 0.1.0
logging:
level: info
format: compact
color: true
endpoint:
base_url: http://localhost:8080
auth_type: none
swagger_file: examples/todo-app/openapi.yamlThen run:
yas-mcp --config config.yaml--mode: Server mode (stdio, http, sse). Default: stdio--swagger-file: Path to OpenAPI specification (required)--adjustments-file: Path to adjustments file for filtering/customization--config: Path to configuration file--endpoint: API endpoint base URL--host: Server host for HTTP/SSE modes--port: Server port for HTTP/SSE modes
Primary MCP mode for direct integration with AI assistants:
yas-mcp --swagger-file api.yaml --mode stdioJSON-RPC over HTTP with session management:
yas-mcp --swagger-file api.yaml --mode http --port 3000Endpoints:
- POST
/mcp- Main JSON-RPC endpoint - GET
/sse- Server-Sent Events stream - DELETE
/session- Session cleanup - GET
/health- Health check
Server-Sent Events for streaming responses:
yas-mcp --swagger-file api.yaml --mode sse --port 3000Filter routes and customize descriptions using YAML:
routes:
- path: /users/me
methods:
- GET
- path: /todos
methods:
- GET
- POST
descriptions:
- path: /todos
updates:
- method: GET
new_description: Retrieve all todo items with optional filteringConfigure OAuth2 in config.yaml:
oauth:
enabled: true
provider: github
client_id: your_client_id
client_secret: your_client_secret
scopes:
- read:user
- user:email
redirect_uri: http://localhost:3000/oauth/callbackSupported providers: github, google, microsoft, generic
Scripts are provided for local Keycloak testing:
# Start Keycloak
docker compose --profile auth up
# Setup Keycloak realm and client
./scripts/setup-keycloak.sh
# Generate OAuth configuration
./scripts/create-config.shcargo test# Start Prism mock server
docker compose up prism
# Run tests
cargo test -- --nocapturesrc/main.rs- Application entry pointsrc/internal/server/- Server implementationssrc/internal/parser/- OpenAPI parsingsrc/internal/requester/- HTTP clientsrc/internal/auth/- OAuth2 implementationsrc/internal/config/- Configuration management
Configuration can be overridden with environment variables using the OPENAPI_MCP_ prefix:
export OPENAPI_MCP_SERVER_PORT=3000
export OPENAPI_MCP_LOGGING_LEVEL=debug
export OPENAPI_MCP_ENDPOINT_BASE_URL=http://api.example.comSee the examples/ directory for sample configurations:
examples/todo-app/- Todo API with adjustments- Docker Compose configurations
- OAuth2 setup scripts
If you have not read the openapi spec that you plan to use, then you may want to run it in a sandbox:
bwrap \
--tmpfs / \
--ro-bind /usr /usr \
--ro-bind /bin /bin \
--ro-bind /lib /lib \
--ro-bind /lib64 /lib64 \
--ro-bind /lib/x86_64-linux-gnu /lib/x86_64-linux-gnu \
--proc /proc \
--dev-bind /dev/null /dev/null \
--tmpfs /tmp \
--ro-bind ~/.cargo ~/.cargo \
--ro-bind ~/.rustup ~/.rustup \
--ro-bind "$(pwd)" /build \
--tmpfs /build/logs \
--tmpfs /build/target \
--ro-bind "$(pwd)/examples/todo-app/openapi.yaml" /config/openapi.yaml \
--ro-bind "$(pwd)/mcp-oauth-config.yaml" /config/mcp-oauth-config.yaml \
--setenv CC /usr/bin/x86_64-linux-gnu-gcc-11 \
--setenv CARGO_TARGET_X86_64_UNKNOWN_LINUX_GNU_LINKER /usr/bin/x86_64-linux-gnu-gcc-11 \
--setenv PATH /usr/bin:/bin \
--chdir /build \
--unshare-all \
--share-net \
--die-with-parent \
cargo run \
--bin yas-mcp \
-- \
--config /config/mcp-oauth-config.yaml \
--swagger-file /config/openapi.yaml \
--mode http
Or, maybe in docker, or better yet don't run it at all on your machine.
What do I mean by this?
What if a tool description had something that attempted to send this to an external webhook?
bwrap --tmpfs / --ro-bind /usr /usr --ro-bind /bin /bin --ro-bind /lib /lib --ro-bind /lib64 /lib64 --unshare-all sh -c "ls /home; cat ~/.ssh/id_rsa"
ls: cannot access '/home': No such file or directory
cat: /home/jm/.ssh/id_rsa: No such file or directory
See LICENSE file for details.
Contributions are welcome. Please ensure tests pass and follow existing code style.