A lightweight MCP server that lets AI agents make authenticated HTTP requests without access to your credentials.
go install github.com/clcollins/shim-mcp/cmd/shim-mcp@latestVerify it installed:
shim-mcp versionCreate the config directory and file with secure permissions — set permissions before writing any content:
mkdir -p ~/.config/shim-mcp
touch ~/.config/shim-mcp/config.yaml
chmod 600 ~/.config/shim-mcp/config.yamlEdit ~/.config/shim-mcp/config.yaml and add at least one service.
This GitHub example assumes your token is in ~/.config/github/token:
services:
github:
base_url: "https://api.github.com"
auth:
type: token
token: {file: "~/.config/github/token"}
headers:
Accept: application/vnd.github.v3+jsonSee Configuration below for all auth types and credential source options.
Register shim-mcp as an MCP server in Claude Code. Use --scope user
so it is available in all projects:
claude mcp add --scope user shim-mcp -- \
shim-mcp serve --config /home/YOUR_USER/.config/shim-mcp/config.yamlReplace /home/YOUR_USER/ with your actual home directory path. The
--config flag requires an absolute path — tilde expansion (~) is
handled inside the config file for credential paths, but the config
file path itself must be absolute.
Then add permission entries to ~/.claude/settings.json so the tools
are allowed without prompting:
{
"permissions": {
"allow": [
"mcp__shim-mcp__http_request",
"mcp__shim-mcp__list_services"
]
}
}Both tools are read-only proxied HTTP requests — credentials never cross the MCP boundary — so they are safe to allow globally.
Start a new Claude Code session. The agent should now have access to two new tools:
-
list_services— call this first to confirm your services are loaded. It returns service names and base URLs (no credentials). -
http_request— make an authenticated request. Try:Use http_request to GET /user from the github serviceThe agent will call shim-mcp, which injects your token and returns the GitHub API response.
If the tools don't appear, check that:
shim-mcpis on your$PATH(runwhich shim-mcpin a terminal)- The config file path in settings.json is absolute and correct
- The config file parses without errors (
shim-mcp serve --config /path/to/config.yamlin a terminal should start without error messages on stderr)
Agent ──[MCP stdio]──> shim-mcp ──[authenticated HTTP]──> API
│
reads credentials
from local files
or env vars
- Claude Code launches shim-mcp as a subprocess via MCP stdio transport
- The agent calls the
http_requesttool with a service name and request parameters - shim-mcp looks up the service, resolves credentials from a local file or environment variable, and injects the appropriate auth header
- The HTTP request is made with Go's
net/httpstdlib - The response is returned with all credential headers scrubbed
Credentials never cross the MCP protocol boundary — they exist only inside the server process.
Make an authenticated HTTP request to a configured service.
| Parameter | Type | Required | Description |
|---|---|---|---|
service |
string | yes | Configured service name |
method |
string | yes | HTTP method (GET, POST, PUT, DELETE, PATCH, HEAD) |
path |
string | no | Path appended to the service base URL |
headers |
object | no | Additional request headers |
query_params |
object | no | Query parameters |
body |
string | no | Request body |
Returns status_code, headers (scrubbed), and body.
Lists configured services and their base URLs. No credentials are exposed.
Services are defined in a YAML config file. Each service specifies a base URL, an auth method, and where to find credentials.
services:
jira:
base_url: "https://jira.example.com"
auth:
type: basic
username: {file: "~/.config/app/creds.json", key: ".email"}
token: {file: "~/.config/app/creds.json", key: ".token"}
headers:
Content-Type: application/json| Type | Header format | Fields |
|---|---|---|
basic |
Authorization: Basic base64(user:token) |
username + token |
bearer |
Authorization: Bearer <token> |
token |
token |
Authorization: token <token> |
token |
header |
Custom via Go template | token + header + template |
Each credential (username, token) is an inline object pointing to
a source:
# Raw text file
token: {file: "~/.config/github/token"}
# JSON file with key extraction (format inferred from .json extension)
token: {file: "~/.config/app/config.json", key: ".api.token"}
# YAML file with key extraction (format inferred from .yml extension)
token: {file: "~/.config/app/config.yml", key: ".credentials.token"}
# Explicit format override (when extension doesn't match content)
token: {file: "~/.config/app/credentials", format: json, key: ".token"}
# Environment variable
token: {env: "API_TOKEN"}See docs/configuration.md for the full reference including key path syntax and validation rules.
- Credentials are resolved at request time, never cached or sent over MCP
- All
Authorizationheaders are scrubbed from responses - Requests are restricted to configured
base_urlprefixes (SSRF prevention) - Stdio transport only — no network listener
- Config file should be
chmod 600
See docs/security.md for the full security model.
# Clone
git clone https://github.com/clcollins/shim-mcp.git
cd shim-mcp
# Build
go build -o bin/shim-mcp ./cmd/shim-mcp
# Run tests
go test ./...
# Run tests with race detector
CGO_ENABLED=1 go test -race ./...
# Install to $GOPATH/bin
go install ./cmd/shim-mcpThis repository follows the conventions defined in CONVENTIONS.md, covering CI, linting, container, Makefile, and documentation standards.
Every meaningful change includes a plan document in docs/plans/. See docs/plans/TEMPLATE.md for the template.
