Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
11 changes: 8 additions & 3 deletions .commitlintrc.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,8 @@ rules:
- config
- output
- clipboard
- mcp
- share
- docs
- ci
- build
Expand All @@ -33,11 +35,14 @@ rules:
- test
- lint
- security
# Allow acronyms (MCP, SDK, HTTP) in subjects; only forbid Title-Case / ALL-CAPS
# subjects, matching the @commitlint/config-conventional default.
subject-case:
- 2
- always
- - sentence-case
- lower-case
- never
- - upper-case
- pascal-case
- start-case
header-max-length:
- 2
- always
Expand Down
18 changes: 17 additions & 1 deletion .cspell.json
Original file line number Diff line number Diff line change
Expand Up @@ -77,7 +77,23 @@
"Zed",
"Aider",
"Gemini",
"commitlintrc"
"commitlintrc",
"mcp",
"MCP",
"stdio",
"systemd",
"Streamable",
"jsonrpc",
"ndjson",
"openssl",
"DynamicUser",
"modelcontextprotocol",
"reverse",
"GOPATH",
"syscalls",
"exfiltrating",
"exfiltration",
"loopback"
],
"ignorePaths": [
"go.mod",
Expand Down
6 changes: 6 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,12 @@ Russian translation: [CHANGELOG.ru.md](CHANGELOG.ru.md).

### Added

- **`ypcli mcp`** — a Model Context Protocol server exposing send/receive to AI
agents (Claude, Codex, Gemini). Tools: `send_secret`, `send_file`,
`receive_secret` (omit with `--read-only`), `list_profiles`, `server_version`.
Serves over stdio or HTTP (`--http`, bearer-token protected). Ships a Claude
Agent Skill (`skills/ypcli/`), per-client configs (`integrations/`), and a
hardened systemd unit (`deploy/`).
- `ypcli send --input-command '<cmd>'` runs any command and sends its raw stdout
as the secret — a generic bridge to any secrets manager (AWS Secrets Manager,
gopass, `pass`, 1Password CLI, …).
Expand Down
6 changes: 6 additions & 0 deletions CHANGELOG.ru.md
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,12 @@ English version: [CHANGELOG.md](CHANGELOG.md).

### Добавлено

- **`ypcli mcp`** — сервер Model Context Protocol, экспонирующий send/receive
ИИ-агентам (Claude, Codex, Gemini). Инструменты: `send_secret`, `send_file`,
`receive_secret` (убирается через `--read-only`), `list_profiles`,
`server_version`. Работает по stdio или HTTP (`--http`, защита bearer-токеном).
Поставляет Claude Agent Skill (`skills/ypcli/`), конфиги для клиентов
(`integrations/`) и hardened systemd-юнит (`deploy/`).
- `ypcli send --input-command '<cmd>'` выполняет любую команду и отправляет её
сырой stdout как секрет — универсальный мост к любому менеджеру секретов
(AWS Secrets Manager, gopass, `pass`, 1Password CLI, …).
Expand Down
1 change: 1 addition & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -133,6 +133,7 @@ a Russian mirror is in [`docs/ru/`](docs/ru/README.md).
| 06 | [Automation](docs/en/06-automation.md) | [ru](docs/ru/06-automation.md) | CI/agents, JSON, exit codes |
| 07 | [Security](docs/en/07-security.md) | [ru](docs/ru/07-security.md) | Crypto model, interoperability |
| 08 | [Development](docs/en/08-development.md) | [ru](docs/ru/08-development.md) | Build, test, lint, release |
| 09 | [MCP server](docs/en/09-mcp.md) | [ru](docs/ru/09-mcp.md) | Expose ypcli to AI agents (Claude/Codex/Gemini) |

## Exit codes

Expand Down
73 changes: 73 additions & 0 deletions deploy/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,73 @@
# Deploying the ypcli MCP server

Two ways to expose ypcli to AI agents (Claude, Codex, Gemini):

- **stdio** (local) — the agent launches `ypcli mcp` as a subprocess. Nothing to
deploy beyond installing the binary and a profile. See
[docs/en/09-mcp.md](../docs/en/09-mcp.md).
- **HTTP** (shared server) — run `ypcli mcp --http` as a service that agents
connect to over the network with a bearer token. That is what this directory
covers.

## Install the binary

```bash
go install github.com/dantte-lp/ypcli/cmd/ypcli@latest
sudo install "$(go env GOPATH)/bin/ypcli" /usr/local/bin/ypcli # or a release binary
```

## Configure

```bash
sudo mkdir -p /etc/ypcli

# 1) Profile config — no plaintext secrets; use token_command for yopass auth.
sudo tee /etc/ypcli/config.yaml >/dev/null <<'YAML'
defaults:
api: https://api.yopass.corp
url: https://yopass.corp
# token_command: vault read -field=token secret/yopass # if the server needs auth
YAML
sudo chmod 0644 /etc/ypcli/config.yaml

# 2) Bearer token for the HTTP endpoint (root-only).
printf 'YPCLI_MCP_TOKEN=%s\n' "$(openssl rand -hex 32)" | sudo tee /etc/ypcli/mcp.env >/dev/null
sudo chmod 0600 /etc/ypcli/mcp.env
```

## Run as a service

```bash
sudo cp deploy/systemd/ypcli-mcp.service /etc/systemd/system/
sudo systemctl daemon-reload
sudo systemctl enable --now ypcli-mcp
systemctl status ypcli-mcp
```

The unit runs under `DynamicUser` with a strict sandbox (`ProtectSystem=strict`,
`NoNewPrivileges`, no capabilities, filtered syscalls) and binds to
`127.0.0.1:8765` by default.

## TLS / exposure

The server speaks plain HTTP and binds to loopback. Put it behind a
TLS-terminating reverse proxy (nginx, Caddy, Traefik) if agents connect from
other hosts, and keep the bearer token secret. Example Caddy:

```caddy
mcp.yopass.corp {
reverse_proxy 127.0.0.1:8765
}
```

## Connect an agent

Point the client at the URL with the bearer token — see
[docs/en/09-mcp.md](../docs/en/09-mcp.md#http-shared-server) and the ready-made
snippets in [`integrations/`](../integrations).

```bash
# Claude Code
claude mcp add --transport http ypcli https://mcp.yopass.corp \
--header "Authorization: Bearer $YPCLI_MCP_TOKEN"
```
44 changes: 44 additions & 0 deletions deploy/systemd/ypcli-mcp.service
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
[Unit]
Description=ypcli MCP server (yopass secret sharing for AI agents)
Documentation=https://github.com/dantte-lp/ypcli
After=network-online.target
Wants=network-online.target

[Service]
Type=simple
# Runs as a transient, unprivileged user with no home or shell.
DynamicUser=yes
# YPCLI_MCP_TOKEN (bearer for the HTTP endpoint) lives here; keep it root:root 0600.
EnvironmentFile=/etc/ypcli/mcp.env
# The profile config (no plaintext secrets — use token_command for auth).
ExecStart=/usr/local/bin/ypcli mcp --http 127.0.0.1:8765 --config /etc/ypcli/config.yaml
Restart=on-failure
RestartSec=2

# --- hardening ---
NoNewPrivileges=yes
ProtectSystem=strict
ProtectHome=yes
PrivateTmp=yes
PrivateDevices=yes
ProtectClock=yes
ProtectKernelTunables=yes
ProtectKernelModules=yes
ProtectKernelLogs=yes
ProtectControlGroups=yes
ProtectProc=invisible
RestrictAddressFamilies=AF_INET AF_INET6
RestrictNamespaces=yes
RestrictRealtime=yes
RestrictSUIDSGID=yes
LockPersonality=yes
MemoryDenyWriteExecute=yes
SystemCallFilter=@system-service
SystemCallErrorNumber=EPERM
SystemCallArchitectures=native
CapabilityBoundingSet=
AmbientCapabilities=
ReadOnlyPaths=/etc/ypcli

[Install]
WantedBy=multi-user.target
16 changes: 16 additions & 0 deletions docs/en/04-cli.md
Original file line number Diff line number Diff line change
Expand Up @@ -93,6 +93,22 @@ endpoint. Servers older than yopass 13.x report `unsupported`.
ypcli version --api https://api.yopass.se --json
```

## `ypcli mcp`

Run an MCP server exposing ypcli's send/receive operations to AI agents. See
[MCP server](09-mcp.md) for the full guide.

| Flag | Description |
|---|---|
| `--http` | serve over HTTP at this address instead of stdio (e.g. `127.0.0.1:8765`) |
| `--http-token` | bearer token required in HTTP mode (`$YPCLI_MCP_TOKEN`) |
| `--read-only` | expose send-only tools (omit `receive_secret`) |

```bash
ypcli mcp # stdio (for a local agent)
YPCLI_MCP_TOKEN=… ypcli mcp --http :8765 # shared HTTP server
```

## `ypcli completion`

Generate a shell completion script for `bash`, `zsh`, `fish`, or `powershell`.
Expand Down
97 changes: 97 additions & 0 deletions docs/en/09-mcp.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,97 @@
# MCP server & agent integration

`ypcli mcp` runs a [Model Context Protocol](https://modelcontextprotocol.io)
server that exposes ypcli's operations as tools, so AI agents (Claude, Codex,
Gemini, …) can share and fetch secrets. It reuses the same crypto and transport
as the CLI, so behavior is identical. Connection settings come from the ypcli
[config profiles](05-configuration.md) on the host.

```mermaid
flowchart LR
A["AI agent<br/>Claude · Codex · Gemini"] -->|MCP tools| M["ypcli mcp<br/>(stdio or HTTP)"]
M -->|client-side OpenPGP| Y["yopass server"]
```

## Tools

| Tool | Purpose |
|---|---|
| `send_secret` | encrypt & publish text → one-time share URL |
| `send_file` | encrypt & publish a file (by path) → share URL |
| `receive_secret` | fetch & decrypt a share URL (or `id`+`key`) — consumes one-time secrets |
| `list_profiles` | list configured server profiles |
| `server_version` | client + yopass server version |

Each tool accepts an optional `profile`. `--read-only` omits `receive_secret`
for send-only deployments.

## Local (stdio)

The agent launches `ypcli mcp` as a subprocess. Install ypcli and configure a
profile first (see [Installation](02-installation.md), [Configuration](05-configuration.md)).

**Claude Code**

```bash
claude mcp add ypcli -- ypcli mcp
```

**Codex** — add to `~/.codex/config.toml`:

```toml
[mcp_servers.ypcli]
command = "ypcli"
args = ["mcp"]
```

**Gemini CLI** — add to `~/.gemini/settings.json`:

```json
{ "mcpServers": { "ypcli": { "command": "ypcli", "args": ["mcp"] } } }
```

Ready-made snippets live in [`integrations/`](https://github.com/dantte-lp/ypcli/tree/master/integrations).

## HTTP (shared server)

Run one server that agents reach over the network with a bearer token:

```bash
YPCLI_MCP_TOKEN=$(openssl rand -hex 32) ypcli mcp --http 127.0.0.1:8765
```

A token is **required** in HTTP mode. Put the server behind a TLS reverse proxy
for remote access; deploy it as a hardened systemd service — see
[`deploy/`](https://github.com/dantte-lp/ypcli/tree/master/deploy). Then point a
client at the URL:

```bash
claude mcp add --transport http ypcli https://mcp.yopass.corp \
--header "Authorization: Bearer $YPCLI_MCP_TOKEN"
```

Codex uses `url` + `bearer_token_env_var`; Gemini uses an `httpUrl` server entry.

## Claude skill

The repo ships a Claude [Agent Skill](https://code.claude.com/docs/en/skills) at
[`skills/ypcli/`](https://github.com/dantte-lp/ypcli/tree/master/skills/ypcli).
Copy it to `~/.claude/skills/ypcli/` so Claude knows when and how to share
secrets with the MCP tools.

## Security

- **`send_file` reads any local file** the caller names (absolute path only). An
autonomous agent that can be prompt-injected could be steered into exfiltrating
sensitive files (SSH keys, cloud credentials). Run the MCP server under a
least-privileged user with a restricted filesystem view — the systemd unit in
[`deploy/`](https://github.com/dantte-lp/ypcli/tree/master/deploy) uses
`ProtectSystem=strict`; for stdio/local agents, launch ypcli from a confined
working directory or omit `send_file` from the client's allowed tools.
- HTTP mode requires a bearer token (constant-time compared); bind to loopback
behind TLS for anything non-local.
- `receive_secret` **consumes** one-time secrets on first fetch — only call it to
reveal (and destroy) a secret.
- Plaintext secrets and tokens are never logged. Tokens come from the profile's
`token_command`, never from disk.
- Use `--read-only` where agents should only publish, never fetch.
1 change: 1 addition & 0 deletions docs/en/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -12,3 +12,4 @@
| 06 | [Automation](06-automation.md) | CI/agents, JSON output, exit codes |
| 07 | [Security](07-security.md) | Cryptographic model, interoperability |
| 08 | [Development](08-development.md) | Build, test, lint, release workflow |
| 09 | [MCP server](09-mcp.md) | Expose ypcli to AI agents (Claude, Codex, Gemini) |
16 changes: 16 additions & 0 deletions docs/ru/04-cli.md
Original file line number Diff line number Diff line change
Expand Up @@ -92,6 +92,22 @@ ypcli config remove work
ypcli version --api https://api.yopass.se --json
```

## `ypcli mcp`

Запустить MCP-сервер, экспонирующий операции send/receive ypcli ИИ-агентам. См.
[MCP-сервер](09-mcp.md) для полного руководства.

| Флаг | Описание |
|---|---|
| `--http` | обслуживать по HTTP на этом адресе вместо stdio (напр. `127.0.0.1:8765`) |
| `--http-token` | bearer-токен, обязательный в HTTP-режиме (`$YPCLI_MCP_TOKEN`) |
| `--read-only` | экспонировать только send-инструменты (без `receive_secret`) |

```bash
ypcli mcp # stdio (для локального агента)
YPCLI_MCP_TOKEN=… ypcli mcp --http :8765 # общий HTTP-сервер
```

## `ypcli completion`

Сгенерировать скрипт автодополнения оболочки для `bash`, `zsh`, `fish` или `powershell`.
Expand Down
Loading
Loading