A lightweight and extensible server for defining and executing API tools using
the MCP protocol.
Supports dynamic HTTP requests, typed arguments, and multiple transports (stdio
, sse
).
You can install the server in one of two ways:
If you have Go installed, run:
go install github.com/AdamShannag/api-mcp-server/cmd/[email protected]
Download a binary from the Releases page.
Flag | Description | Default |
---|---|---|
--transport , -t |
Transport type: stdio or sse |
stdio |
--config , -c |
Path to JSON tool configuration | ./config.json |
--version , -v |
API MCP Server version | - |
--metrics , -m |
Enable Prometheus metrics and health check server | - |
--metrics-port |
Metrics and health check server port | 8080 |
Variable | Description | Default |
---|---|---|
API_MCP_HOST |
SSE host to bind to | 127.0.0.1 |
API_MCP_PORT |
SSE port to bind to | 13080 |
API_MCP_SSE_API_KEY |
Optional Bearer token for auth | (none) |
LOG_LEVEL |
Sets the minimum logging level (DEBUG , INFO , WARN , ERROR ) |
INFO |
The tool configuration file supports environment variable substitution using the syntax:
{{env VAR_NAME:default_value}}
At runtime, placeholders are replaced with the corresponding environment variable. If the variable is not set, the
default_value
is used instead.
"host": "{{env API_HOST:jsonplaceholder.typicode.com}}"
Uses the value of API_HOST
if set, otherwise falls back to the default.
"Authorization": "Bearer {{env API_KEY:not-set}}"
Uses API_KEY
or "not-set"
if not defined.
Before running the server, set any required environment variables:
export API_HOST=myapi.example.com
export API_KEY=supersecret123
When using the SSE transport, you can optionally secure the endpoint using a Bearer token by setting the
API_MCP_SSE_API_KEY
environment variable.
Example:
export API_MCP_SSE_API_KEY="your-secret-key"
api-mcp-server --transport sse --config ./demo.tools.json
Incoming SSE connections must then provide the matching token in the Authorization
header.
The server accepts a JSON configuration file defining one or more tools. Each tool includes metadata (name
,
description
), HTTP request information, and a list of args
that define the input values required from the LLM.
Each tool config includes:
- A unique
name
- A
description
shown to the LLM - A
request
object describing the HTTP call - A list of
args
to define expected inputs
Arguments are inputs collected from the LLM. Each one may be used in one or more parts of the request:
- Path Parameters → replaced directly inside the
endpoint
- Query Parameters → automatically added to the URL
- Body → inserted as the raw request body string
The host
is the target API domain (e.g., gitlab.com
).
"host": "{{env GITLAB_API_HOST:gitlab.com}}"
The HTTP method (GET
, POST
, PUT
, etc.).
"method": "POST"
Used to replace variables in the endpoint
. For example:
"endpoint": "/api/v4/projects/:project_id/pipeline",
"pathParams": ["project_id"]
With project_id = "MyProject/test"
, the final endpoint becomes:
/api/v4/projects/MyProject%2Ftest/pipeline
Keys listed here are automatically appended to the endpoint as query string parameters:
"endpoint": "/api/v4/projects/:project_id/pipeline",
"queryParams": ["ref"]
With ref = "main"
, the result is:
/api/v4/projects/MyProject%2Ftest/pipeline?ref=main
The body
field maps to a single argument name. Its value will be used as the raw request body string.
Example:
"body": "issue_payload"
Given this argument:
{
"name": "issue_payload",
"type": "string",
"required": true,
"description": "A JSON object like {\"title\": \"Bug report\"}"
}
The body sent to the server will be the exact string value of issue_payload
.
Define static or dynamic HTTP headers to include in the request, e.g., tokens or content type:
"headers": {
"PRIVATE-TOKEN": "{{env GITLAB_TOKEN:not-set}}",
"Content-Type": "application/json"
}
If secure: true
, the request uses https
. If omitted or false
, it uses http
.
{
"name": "TriggerPipeline",
"description": "Triggers a pipeline in GitLab for a specific project and branch.",
"request": {
"host": "{{env GITLAB_API_HOST:gitlab.com}}",
"method": "POST",
"secure": true,
"endpoint": "/api/v4/projects/:project_id/pipeline",
"headers": {
"PRIVATE-TOKEN": "{{env GITLAB_TOKEN:not-set}}"
},
"queryParams": [
"ref"
],
"pathParams": [
"project_id"
]
},
"args": [
{
"name": "project_id",
"type": "string",
"required": true,
"description": "..."
},
{
"name": "ref",
"type": "string",
"required": true,
"description": "..."
}
]
}
If project_id = "MyProject/test"
and ref = "main"
, the final HTTP request is:
POST https://gitlab.com/api/v4/projects/MyProject%2Ftest/pipeline?ref=main
Headers:
PRIVATE-TOKEN: <value from GITLAB_TOKEN>
This repository includes several example tool configurations to demonstrate different use cases. These are not ready-to-use APIs but serve as references:
-
GitLab Issues Tools for listing and creating issues in a GitLab project. See examples/gitlab
-
JSONPlaceholder Todos Tools interacting with the JSONPlaceholder public API. See examples/jsonplaceholder
If you have any questions or want to contribute, feel free to open an issue or PR.