Skip to main content
Glama
README.md
# langextract-mcp

`langextract-mcp` is an independent, standalone stdio MCP server that exposes Google LangExtract through three bounded tools:

- `langextract_extract`: model-assisted extraction from literal text, with source spans.
- `langextract_visualize`: return escaped interactive HTML for an annotated payload.
- `langextract_status`: safe configuration and limit report.

This is an independent wrapper. It is not affiliated with or supported by Google. It is not published to PyPI.

The server does not read caller files, fetch caller URLs, accept model URLs, accept credentials, or write output files. `langextract_extract` wraps text in a `langextract.core.data.Document` iterable and passes `fetch_urls=False`, including on LangExtract versions where URL-shaped strings could otherwise be significant.

## Install and run from a clone

Requirements: Python 3.11+ and [uv](https://docs.astral.sh/uv/).

    git clone https://github.com/CuriosityQuantified/langextract-mcp.git
    cd /absolute/path/to/langextract-mcp
    uv sync --frozen --all-groups
    uv run --frozen langextract-mcp

No MCP client registration occurs automatically. For an MCP client that uses `mcpServers`, add a server entry manually:

```json
{
  "mcpServers": {
    "langextract": {
      "command": "uv",
      "args": [
        "--directory",
        "/absolute/path/to/langextract-mcp",
        "run",
        "--frozen",
        "langextract-mcp"
      ]
    }
  }
}
```

## Optional Git-installed launch

After the `v0.1.0` tag exists, an MCP client can launch the tagged source directly with uvx:

    uvx --from git+https://github.com/CuriosityQuantified/langextract-mcp@v0.1.0 langextract-mcp

This command installs from Git, not PyPI. It requires network access and does not replace a clone when you need the frozen repository lockfile for reproducible development or checks.

## Hermes configuration

Add this to the appropriate Hermes profile, replacing the example path with your clone's absolute path:

```yaml
mcp_servers:
  langextract:
    command: uv
    args: ["--directory", "/absolute/path/to/langextract-mcp", "run", "--frozen", "langextract-mcp"]
    timeout: 180
    sampling:
      enabled: true
      max_tokens_cap: 1024
      timeout: 120
      max_tool_rounds: 0
```

Use an absolute path to `uv` if your MCP host does not inherit your shell's PATH. Reload the MCP connection or start a fresh host session after configuration.

## Inference providers

The default (`LANGEXTRACT_MCP_PROVIDER=sampling`) uses the MCP host's sampling capability. The host must implement MCP sampling (`sampling/createMessage`); this server asks for a single text response, no tools, no included context, and at most 1,024 generated tokens. This is the preferred mode because the server does not need a new API key.

An operator may instead set `LANGEXTRACT_MCP_PROVIDER` to `gemini`, `openai`, or `ollama`, and optionally `LANGEXTRACT_MCP_MODEL`. OpenAI mode requires the optional extra and a locked install:

    uv sync --frozen --all-groups --extra openai

Credentials remain server environment only: `LANGEXTRACT_API_KEY` for Gemini and `OPENAI_API_KEY` for OpenAI. Ollama uses its default local endpoint; the tool never receives a URL or provider kwargs. Network providers can disclose submitted text to the configured provider and can charge for tokens. Extraction passes multiply inference cost; smaller character buffers can cause more calls. Direct provider calls use one worker, disable retries where supported, and set a 120-second request timeout. Direct inference checks cancellation and a 100-request/120-second budget before each new request. An already-blocking SDK request may still run until its request timeout; cancellation prevents later requests rather than forcibly terminating the SDK.

This project deliberately does not load `.env` files; set environment variables in the host process.

## Grounding and visualization

`grounded_only=true` is the default. It removes model outputs LangExtract could not align to source text. A retained span may have `match_exact`, `match_greater`, `match_lesser`, or `match_fuzzy`; `exact_match` is computed by direct character comparison of `extraction_text` and `source_substring`. Every returned span includes `source_substring`, the literal substring at the reported character interval. Missing interval/status/substrings means the model output was not grounded and appears only when `grounded_only=false`.

Visualization accepts payload JSON, not paths. The wrapper bounds the payload before rendering and re-encodes the released renderer's embedded JSON with script-safe escaping; visible text, classes, and attributes are HTML-escaped. Treat returned HTML as display content, not trusted executable application code.

Extraction quality depends on the host model and examples. An empty extraction list is not proof that no relevant entities exist. Models may repeat few-shot examples; `grounded_only` removes outputs without a source span, not every possible semantic mistake. Review the actual source substring and `exact_match` flag for important uses.

## Calling the extraction tool

```json
{
  "text": "Grace Hopper visited London.",
  "prompt_description": "Extract people and cities using exact source text, in order of appearance.",
  "examples": [{
    "text": "Ada Lovelace visited Paris.",
    "extractions": [
      {"extraction_class": "person", "extraction_text": "Ada Lovelace"},
      {"extraction_class": "city", "extraction_text": "Paris"}
    ]
  }],
  "visualization": true
}
```

Pass the returned annotated document to `langextract_visualize` as `annotated_document` to render it separately. The HTML is returned as text; saving it is the client's choice, not a server-side file operation.

## Checks

    uv sync --frozen --all-groups --all-extras
    uv run --frozen ruff check .
    uv run --frozen ruff format --check .
    uv run --frozen pytest
    uv run --frozen python -m build --no-isolation
    uv venv --clear .wheel-venv
    uv pip install --python .wheel-venv/bin/python dist/*.whl
    .wheel-venv/bin/python -c "import langextract_mcp.server"

For a real local-host smoke test, set `LX_SAMPLING_COMMAND` to a command that reads the LangExtract prompt on stdin and emits a real JSON extraction envelope, then run:

    uv run --frozen python example/real_sampling_smoke.py

The smoke script is not a product provider and does not claim fixture output is live inference.

## License

Apache-2.0. The repository release must include the `LICENSE` file.

TDQS

A3.5/5.0

Scored across 3 tools

Disambiguation5/5

The three tools serve clearly distinct purposes: extraction, server status, and visualization. There is no overlap in functionality, and an agent can easily select the right tool based on the task.

Naming Consistency4/5

All tools share the consistent 'langextract_' prefix followed by a single word. However, 'extract' and 'visualize' are verbs while 'status' is a noun, a minor deviation from a pure verb_noun pattern.

Tool Count5/5

Three tools is well within the typical 3-15 range and each tool has a clear, non-redundant role. The server is focused and does not appear to have unnecessary or missing tools for its scope.

Completeness4/5

The core extraction, status, and visualization operations are covered, providing a complete basic workflow. Minor gaps exist, such as batch extraction, schema listing, or configuration updates, but agents can work around them.

Maintenance

ActivityMaintained
ResponsivenessNo issues