oxo-call 0.11.0

Model-intelligent orchestration for CLI bioinformatics — call any tool with LLM intelligence
Documentation
# MCP Skill Provider

oxo-call supports the **Model Context Protocol (MCP)** as a skill source.
Any MCP-compatible server that exposes bioinformatics skill resources can act
as an organisational or project-scoped skill library, queried automatically
when oxo-call looks for a skill.

---

## What is MCP?

The [Model Context Protocol](https://modelcontextprotocol.io) is an open
standard (originally from Anthropic, now widely adopted) that lets AI clients
connect to external data and tool servers using a uniform JSON-RPC interface.
oxo-call uses MCP's **resources** API to discover and retrieve skill content
from remote servers — no new dependencies required (HTTP + JSON are already
used by the LLM client).

---

## Load Priority

When oxo-call looks for a skill it checks sources in this order (highest wins):

| Priority | Source | Location |
|----------|--------|----------|
| 1 | **User-defined** | `~/.config/oxo-call/skills/<tool>.md` |
| 2 | **Community-installed** | `~/.local/share/oxo-call/skills/<tool>.md` |
| 3 | **MCP servers** | Registered in `config.toml` under `[mcp]` |
| 4 | **Built-in** | Compiled into the binary |

MCP skills are only queried when no higher-priority skill is found for the
requested tool, keeping latency impact minimal for well-covered tools.

---

## MCP Server Contract

An MCP server acting as a skill provider must implement three JSON-RPC methods:

### `initialize`

Standard MCP handshake. oxo-call sends its client info and accepts any
response conforming to the MCP 2024-11-05 protocol version.

### `resources/list`

Lists available skill resources. oxo-call recognises skill resources in two ways:

1. **Preferred — `skill://` URI scheme**
   ```json
   {
     "uri": "skill://samtools",
     "name": "samtools",
     "description": "Suite of programs for SAM/BAM/CRAM handling",
     "mimeType": "text/markdown"
   }
   ```

2. **Fallback — `text/markdown` MIME type**
   Any resource with `"mimeType": "text/markdown"` is treated as a skill.
   The resource `"name"` field is used as the tool name.

### `resources/read`

Returns the Markdown content for a given URI.

```json
// Request
{ "jsonrpc": "2.0", "id": 3, "method": "resources/read",
  "params": { "uri": "skill://samtools" } }

// Response
{ "jsonrpc": "2.0", "id": 3,
  "result": { "contents": [{ "uri": "skill://samtools",
                              "text": "---\nname: samtools\n...",
                              "mimeType": "text/markdown" }] } }
```

The `text` field must contain valid oxo-call skill Markdown (YAML front-matter
followed by `## Concepts`, `## Pitfalls`, and `## Examples` sections).
Legacy TOML format is also accepted as a fallback.

---

## Transport

oxo-call uses **stateless HTTP POST** (no SSE session required):

```
POST <server-url>/mcp HTTP/1.1
Content-Type: application/json
Accept: application/json
MCP-Protocol-Version: 2024-11-05
Authorization: Bearer <api-key>   # only if api_key is configured

{"jsonrpc":"2.0","id":1,"method":"initialize","params":{...}}
```

If the server URL already ends in `/mcp`, it is used as-is; otherwise `/mcp`
is appended automatically.

**Timeout**: 5 seconds per request. Network errors are silently ignored (the
next source in the priority chain is tried).

---

## Configuration

Register MCP servers in `~/.config/oxo-call/config.toml`:

```toml
[[mcp.servers]]
url  = "http://localhost:3000"
name = "local-skills"

[[mcp.servers]]
url     = "https://skills.example.org"
name    = "org-skills"
api_key = "your-secret-token"
```

Or manage them with the CLI:

```bash
# Register a server
oxo-call skill mcp add http://localhost:3000 --name local-skills

# Register an authenticated server
oxo-call skill mcp add https://skills.example.org \
    --name org-skills --api-key your-secret-token

# List registered servers
oxo-call skill mcp list

# Test connectivity
oxo-call skill mcp ping

# Remove a server
oxo-call skill mcp remove local-skills
```

---

## Building an MCP Skill Server

Any HTTP server that implements the three JSON-RPC methods above qualifies.
Below is a minimal example in Python using the
[`mcp`](https://pypi.org/project/mcp/) SDK:

```python
from mcp.server.fastmcp import FastMCP
from pathlib import Path

mcp = FastMCP("my-skills")
SKILLS_DIR = Path("./skills")   # directory of .md files

@mcp.resource("skill://{tool}")
def get_skill(tool: str) -> str:
    """Serve a skill Markdown file."""
    path = SKILLS_DIR / f"{tool}.md"
    if not path.exists():
        raise FileNotFoundError(f"No skill for '{tool}'")
    return path.read_text()

if __name__ == "__main__":
    mcp.run(transport="streamable-http", port=3000)
```

Skills served must follow the [oxo-call skill format](./skill-system.md).

---

## Verification

After registering a server:

```bash
# Show all skills including MCP sources
oxo-call skill list

# Show a skill from an MCP server
oxo-call skill show mytool

# Ping all registered servers
oxo-call skill mcp ping
```

`skill list` shows MCP-sourced skills with a yellow `mcp:<server-name>` label.
`skill mcp ping` reports each server's name, version, and skill count.

---

## Security Considerations

- **api_key** is stored in plain text in `config.toml`.  Restrict file
  permissions (`chmod 600 ~/.config/oxo-call/config.toml`).
- Only `http://` and `https://` URLs are supported.
- Skill content from MCP servers is parsed and validated before use; invalid
  content is silently skipped.
- oxo-call does not execute any code returned by MCP servers.  Skill content
  is only injected into LLM prompts.

See [Security Considerations](./security-considerations.md) for the full security model.