Metadata-Version: 2.4
Name: pulselink-mcp
Version: 1.0.1
Summary: PulseLink — keyless open-web & social research source (MCP Server + A2A Server)
Author-email: Audel Rouhi <knucklessg1@gmail.com>
License: MIT
Classifier: Development Status :: 4 - Beta
Classifier: License :: OSI Approved :: MIT License
Classifier: Environment :: Console
Classifier: Operating System :: POSIX :: Linux
Classifier: Programming Language :: Python :: 3
Requires-Python: <3.15,>=3.11
Description-Content-Type: text/markdown
License-File: LICENSE
Requires-Dist: agent-utilities>=1.0.0
Requires-Dist: python-dotenv>=1.0.0
Provides-Extra: mcp
Requires-Dist: agent-utilities[mcp]>=1.0.0; extra == "mcp"
Provides-Extra: agent
Requires-Dist: agent-utilities[agent,logfire]>=1.0.0; extra == "agent"
Provides-Extra: youtube
Requires-Dist: yt-dlp>=2024.0; extra == "youtube"
Provides-Extra: feeds
Requires-Dist: feedparser>=6.0; extra == "feeds"
Provides-Extra: audio
Requires-Dist: faster-whisper>=1.0; extra == "audio"
Provides-Extra: sources
Requires-Dist: pulselink-mcp[feeds,youtube]>=1.0.1; extra == "sources"
Provides-Extra: all
Requires-Dist: pulselink-mcp[agent,audio,feeds,logfire,mcp,youtube]>=1.0.1; extra == "all"
Provides-Extra: test
Requires-Dist: pytest-xdist>=3.6.0; extra == "test"
Requires-Dist: pytest; extra == "test"
Requires-Dist: pytest-asyncio; extra == "test"
Requires-Dist: pytest-cov; extra == "test"
Requires-Dist: feedparser>=6.0; extra == "test"
Dynamic: license-file

# PulseLink MCP
## CLI or API | MCP | Agent

![PyPI - Version](https://img.shields.io/pypi/v/pulselink-mcp)
![MCP Server](https://badge.mcpx.dev?type=server 'MCP Server')
![PyPI - Downloads](https://img.shields.io/pypi/dd/pulselink-mcp)
![GitHub Repo stars](https://img.shields.io/github/stars/Knuckles-Team/pulselink-mcp)
![PyPI - License](https://img.shields.io/pypi/l/pulselink-mcp)
![GitHub last commit (by committer)](https://img.shields.io/github/last-commit/Knuckles-Team/pulselink-mcp)

*Version: 1.0.1*

> **Documentation** — Installation, deployment, usage across the API, CLI, and MCP
> interfaces, the integrated A2A agent server, and guidance for provisioning the
> backing platform are maintained in the
> [official documentation](https://knuckles-team.github.io/pulselink-mcp/).

---

## Overview

**PulseLink MCP MCP Server + A2A Agent**

PulseLink — keyless open-web & social research source (MCP Server + A2A Server)

This repository is actively maintained - Contributions are welcome!

## MCP

### MCP Configuration Examples

<!-- MCP-CONFIG-EXAMPLES:START -->

> **Install the slim `[mcp]` extra.** All examples install `pulselink-mcp[mcp]` — the
> MCP-server extra that pulls only the FastMCP / FastAPI tooling (`agent-utilities[mcp]`).
> It deliberately **excludes** the heavy agent runtime (`pydantic-ai`, the epistemic-graph
> engine, `dspy`, `llama-index`), so `uvx` / container installs are far smaller. Use the
> full `[agent]` extra only when you need the integrated Pydantic AI agent.

#### stdio Transport (local IDEs — Cursor, Claude Desktop, VS Code)

```json
{
  "mcpServers": {
    "pulselink-mcp": {
      "command": "uvx",
      "args": [
        "--from",
        "pulselink-mcp[mcp]",
        "pulselink-mcp"
      ],
      "env": {
        "MCP_TOOL_MODE": "condensed",
        "PULSETOOL": "True",
        "XAI_BASE_URL": "https://api.x.ai/v1",
        "XAI_SEARCH_MODEL": "grok-4.3"
      }
    }
  }
}
```

#### Streamable-HTTP Transport (networked / production)

```json
{
  "mcpServers": {
    "pulselink-mcp": {
      "command": "uvx",
      "args": [
        "--from",
        "pulselink-mcp[mcp]",
        "pulselink-mcp",
        "--transport",
        "streamable-http",
        "--port",
        "8000"
      ],
      "env": {
        "TRANSPORT": "streamable-http",
        "HOST": "0.0.0.0",
        "PORT": "8000",
        "MCP_TOOL_MODE": "condensed",
        "PULSETOOL": "True",
        "XAI_BASE_URL": "https://api.x.ai/v1",
        "XAI_SEARCH_MODEL": "grok-4.3"
      }
    }
  }
}
```

Alternatively, connect to a pre-deployed Streamable-HTTP instance by `url`:

```json
{
  "mcpServers": {
    "pulselink-mcp": {
      "url": "http://localhost:8000/pulselink-mcp/mcp"
    }
  }
}
```

Deploying the Streamable-HTTP server via Docker:

```bash
docker run -d \
  --name pulselink-mcp-mcp \
  -p 8000:8000 \
  -e TRANSPORT=streamable-http \
  -e HOST=0.0.0.0 \
  -e PORT=8000 \
  -e MCP_TOOL_MODE=condensed \
  -e PULSETOOL=True \
  -e XAI_BASE_URL=https://api.x.ai/v1 \
  -e XAI_SEARCH_MODEL=grok-4.3 \
  knucklessg1/pulselink-mcp:mcp
```

_Auto-generated from the code-read env surface (`MCP_TOOL_MODE` + package vars) — do not edit._
<!-- MCP-CONFIG-EXAMPLES:END -->

<!-- BEGIN GENERATED: additional-deployment-options -->
### Additional Deployment Options

`pulselink-mcp` can also run as a **local container** (Docker / Podman / `uv`) or be
consumed from a **remote deployment**. The
[Deployment guide](https://knuckles-team.github.io/pulselink-mcp/deployment/) has full,
copy-paste `mcp_config.json` for all four transports — **stdio**, **streamable-http**,
**local container / uv**, and **remote URL**:

- **Local container / uv** — launch the server from `mcp_config.json` via `uvx`,
  `docker run`, or `podman run`, or point at a local streamable-http container by `url`.
- **Remote URL** — connect to a server deployed behind Caddy at
  `http://pulselink-mcp.arpa/mcp` using the `"url"` key.
<!-- END GENERATED: additional-deployment-options -->

## Available MCP Tools

This table is auto-generated from the live server — do not edit by hand.

<!-- MCP-TOOLS-TABLE:START -->

#### Condensed action-routed tools (default — `MCP_TOOL_MODE=condensed`)

| MCP Tool | Toggle Env Var | Description |
|----------|----------------|-------------|
| `pulse_fetch` | `PULSETOOL` | Fetch one item (full text/body/transcript). CONCEPT:PULSE-001 |
| `pulse_list` | `PULSETOOL` | List items from a source channel/feed. CONCEPT:PULSE-001 |
| `pulse_search` | `PULSETOOL` | Search a source and return normalized documents. CONCEPT:PULSE-001 |
| `pulse_status` | `PULSETOOL` | Per-source backend + credential health (the doctor). CONCEPT:PULSE-001 |
| `pulse_transcribe` | `PULSETOOL` | Transcribe video/audio to text. CONCEPT:PULSE-005 |

#### Verbose 1:1 API-mapped tools (`MCP_TOOL_MODE=verbose` or `both`)

<details>
<summary>6 per-operation tools — one per public API method (click to expand)</summary>

| MCP Tool | Toggle Env Var | Description |
|----------|----------------|-------------|
| `pulselink_fetch` | `PULSE_LINK_CLIENTTOOL` | Invoke the fetch operation. |
| `pulselink_list_items` | `PULSE_LINK_CLIENTTOOL` | Invoke the list_items operation. |
| `pulselink_search` | `PULSE_LINK_CLIENTTOOL` | Invoke the search operation. |
| `pulselink_sources` | `PULSE_LINK_CLIENTTOOL` | Invoke the sources operation. |
| `pulselink_status` | `PULSE_LINK_CLIENTTOOL` | Invoke the status operation. |
| `pulselink_transcribe` | `PULSE_LINK_CLIENTTOOL` | Invoke the transcribe operation. |

</details>

_5 action-routed tool(s) (default) · 6 verbose 1:1 tool(s). Each is enabled unless its `<DOMAIN>TOOL` toggle is set false; `MCP_TOOL_MODE` selects the surface (`condensed` default · `verbose` 1:1 · `both`). Auto-generated — do not edit._
<!-- MCP-TOOLS-TABLE:END -->

## Environment Variables

Every variable the server reads.

### MCP server / transport
| Variable | Description | Default |
|----------|-------------|---------|
| `TRANSPORT` | `stdio`, `streamable-http`, or `sse` | `stdio` |
| `HOST` | Bind host (HTTP transports) | `0.0.0.0` |
| `PORT` | Bind port (HTTP transports) | `8000` |
| `MCP_TOOL_MODE` | Tool surface: `condensed`, `verbose`, or `both` | `condensed` |
| `MCP_ENABLED_TOOLS` / `MCP_DISABLED_TOOLS` | Comma-separated tool allow/deny list | — |
| `MCP_ENABLED_TAGS` / `MCP_DISABLED_TAGS` | Comma-separated tag allow/deny list | — |
| `DEBUG` | Verbose logging | `False` |
| `PYTHONUNBUFFERED` | Unbuffered stdout (recommended in containers) | `1` |

### X / xAI Live Search (optional)
Used by the X source backend; all optional with sensible defaults.

| Variable | Description | Default |
|----------|-------------|---------|
| `XAI_BASE_URL` | xAI API base URL | `https://api.x.ai/v1` |
| `XAI_SEARCH_MODEL` | Model used for X live search | `grok-4.3` |
| `XAI_SEARCH_TIMEOUT_SECONDS` | Per-request timeout (seconds) | `180` |
| `XAI_SEARCH_RETRIES` | Retry attempts on failure | `2` |

### Source credentials (keyless-first)
| Variable | Description | Default |
|----------|-------------|---------|
| `SOURCE_CREDENTIALS` | JSON object mapping a source → credential descriptor (secret values are URI refs resolved via the secrets backend: `vault://`, `env://`, `sqlite://`). Keyless sources (youtube, web, rss, news, hackernews, v2ex, bilibili) need nothing here; auth-laddered sources (x, reddit, github, exa…) light up higher-fidelity backends when set. | — |

### Tool toggles
Each action-routed tool can be disabled individually via its toggle env var (set to `false`).
The full list is in the [Available MCP Tools](#available-mcp-tools) table above.

| Variable | Description | Default |
|----------|-------------|---------|
| `PULSETOOL` | Enable the PulseLink source tools (`pulse_search` / `pulse_list` / `pulse_fetch` / `pulse_transcribe` / `pulse_status`) | `True` |

### Telemetry & governance
| Variable | Description | Default |
|----------|-------------|---------|
| `ENABLE_OTEL` | Enable OpenTelemetry export | `True` |
| `OTEL_EXPORTER_OTLP_ENDPOINT` | OTLP collector endpoint | — |
| `OTEL_EXPORTER_OTLP_PUBLIC_KEY` / `OTEL_EXPORTER_OTLP_SECRET_KEY` | OTLP auth keys | — |
| `OTEL_EXPORTER_OTLP_PROTOCOL` | OTLP protocol (e.g. `http/protobuf`) | — |
| `EUNOMIA_TYPE` | Authorization mode: `none`, `embedded`, `remote` | `none` |
| `EUNOMIA_POLICY_FILE` | Embedded policy file | `mcp_policies.json` |
| `EUNOMIA_REMOTE_URL` | Remote Eunomia server URL | — |

### Agent CLI (full `[agent]` runtime only)
| Variable | Description | Default |
|----------|-------------|---------|
| `MCP_URL` | URL of the MCP server the agent connects to | `http://localhost:8000/mcp` |
| `PROVIDER` | LLM provider (e.g. `openai`) | `openai` |
| `MODEL_ID` | Model id (e.g. `gpt-4o`) | `gpt-4o` |
| `ENABLE_WEB_UI` | Serve the AG-UI web interface | `True` |

See [`.env.example`](.env.example) for a copy-paste starting point.

## Installation

Pick the extra that matches what you want to run:

| Extra | Installs | Use when |
|-------|----------|----------|
| `pulselink-mcp[mcp]` | Slim MCP server only (`agent-utilities[mcp]` — FastMCP/FastAPI) | You only run the **MCP server** (smallest install / image) |
| `pulselink-mcp[agent]` | Full agent runtime (`agent-utilities[agent,logfire]` — Pydantic AI + the epistemic-graph engine) | You run the **integrated agent** |
| `pulselink-mcp[all]` | Everything (`mcp` + `agent` + `logfire` + the `youtube`/`feeds`/`audio` source extras) | Development / both surfaces |

```bash
# MCP server only (recommended for tool hosting — slim deps)
uv pip install "pulselink-mcp[mcp]"

# Full agent runtime (Pydantic AI + epistemic-graph engine)
uv pip install "pulselink-mcp[agent]"

# Everything (development)
uv pip install "pulselink-mcp[all]"      # or: python -m pip install "pulselink-mcp[all]"
```

> The optional source extras (`youtube` → `yt-dlp`, `feeds` → `feedparser`,
> `audio` → `faster-whisper`) are lazy-imported; the keyless web/forum/news/dev
> sources need none of them. Install `pulselink-mcp[sources]` for `youtube` + `feeds`.

### Container images (`:mcp` vs `:agent`)

One multi-stage `docker/Dockerfile` builds two right-sized images, selected by `--target`:

| Image tag | Build target | Contents | Entrypoint |
|-----------|--------------|----------|------------|
| `knucklessg1/pulselink-mcp:mcp` | `--target mcp` | `pulselink-mcp[mcp]` — **slim**, no engine/`pydantic-ai`/`dspy`/`llama-index`/`tree-sitter` | `pulselink-mcp` |
| `knucklessg1/pulselink-mcp:latest` | `--target agent` (default) | `pulselink-mcp[agent]` — **full** agent runtime + epistemic-graph engine | `pulselink-agent` |

```bash
docker build --target mcp   -t knucklessg1/pulselink-mcp:mcp    docker/   # slim MCP server
docker build --target agent -t knucklessg1/pulselink-mcp:latest docker/   # full agent
```

`docker/mcp.compose.yml` runs the slim `:mcp` server; `docker/agent.compose.yml` runs the
agent (`:latest`) with a co-located `:mcp` sidecar.

### Knowledge-graph database (`epistemic-graph`)

The **full agent** (`[agent]` / `:latest`) embeds the **epistemic-graph** engine (pulled in
transitively via `agent-utilities[agent]`). For production — or to share one knowledge graph
across multiple agents — run **epistemic-graph as its own database container** and point the
agent at it instead of embedding it. Deployment recipes (single-node + Raft HA), connection
config, and the full database architecture (with diagrams) are documented in the
[epistemic-graph deployment guide](https://knuckles-team.github.io/epistemic-graph/deployment/).
The slim `[mcp]` server does **not** require the database.


<!-- BEGIN agent-os-genesis-deploy (generated; do not edit between markers) -->

## Deploy with `agent-os-genesis`

This package can be provisioned for you — skill-guided — by the **`agent-os-genesis`**
universal skill (its *single-package deploy mode*): it picks your install method, seeds
secrets to OpenBao/Vault (or `.env`), trusts your enterprise CA, registers the MCP
server, and verifies it — the same machinery that stands up the whole Agent OS, narrowed
to just this package. Ask your agent to **"deploy `pulselink-mcp` with agent-os-genesis"**.

| Install mode | Command |
|------|---------|
| Bare-metal, prod (PyPI) | `uvx pulselink-mcp` · or `uv tool install pulselink-mcp` |
| Bare-metal, dev (editable) | `uv pip install -e ".[all]"` · or `pip install -e ".[all]"` |
| Container, prod | deploy `knucklessg1/pulselink-mcp:latest` via docker-compose / swarm / podman / podman-compose / kubernetes |
| Container, dev (editable) | deploy `docker/compose.dev.yml` (source-mounted at `/src`; edits live on restart) |

Secrets are read-existing + seeded via `vault_sync` — you are only prompted for what's missing.

<!-- END agent-os-genesis-deploy -->
