Skip to main content
Glama
README.md
# mdMCP

Turn a Markdown file into a local MCP server, with zero dependencies.

```
pip install markdown-mcp-server
```

## Quickstart

**1. Write a tool file:**

```markdown
## Tool: health_check
Check if a URL is reachable.
### Parameters
- url (string, required): URL to check
### Execute
\```bash
STATUS=$(curl -sf -o /dev/null -w '%{http_code}' -m 5 "$MDMCP_URL")
echo "HTTP $STATUS"
\```
```

**2. Serve it:**

```bash
mdmcp serve tools.md
```

**3. Connect to Claude Code:**

```json
{
  "mcpServers": {
    "my-tools": {
      "command": "mdmcp",
      "args": ["serve", "tools.md"]
    }
  }
}
```

That's it. Your Markdown is now an MCP server.

## How it works

- `## Tool: name` defines a tool
- `### Parameters` defines input schema (envvar-based, no string interpolation)
- `### Execute` contains a bash script inside a fenced code block
- Parameters are passed as `$MDMCP_<NAME>` environment variables

## Commands

```bash
mdmcp list tools.md              # List available tools
mdmcp validate tools.md          # Validate tool definitions
mdmcp run tools.md tool_name '{}'  # Run a tool once
mdmcp serve tools.md             # Start MCP stdio server
```

## Security

- **Minimal env**: only PATH, HOME, USER, SHELL, LANG, TERM are inherited. API keys and tokens are NOT exposed to tool scripts.
- **No string interpolation**: parameters are passed as environment variables, not injected into shell code.
- **Required param validation**: missing required parameters return an error before execution.
- **Timeout + process cleanup**: 30s timeout with process group kill to prevent zombies.

## Tips

- Always quote `"$MDMCP_VAR"` in bash to prevent word splitting
- Use `${MDMCP_VAR:-default}` for optional params with bash-side defaults
- You can use `python3 -c` inside bash for complex logic (see `examples/data-tools.md`)
- Use `set -eu` at the top of scripts for safer execution

## Examples

See the [`examples/`](examples/) directory:

- **ops-tools.md** — disk usage, port check, git log, docker status, health check
- **dev-tools.md** — find TODOs, run linter, check port (from Codex dogfood)
- **data-tools.md** — CSV summary, JSON inspect, file diff (from Gemini dogfood)

## Known limitations

- Execute blocks only support ` ``` ` fences (not `~~~`)
- Parameter names must be `\w+` (no spaces or special chars)
- Nested ` ``` ` inside heredocs will confuse the parser
- All parameter values are strings in bash; cast manually if needed

## License

MIT