Metadata-Version: 2.5
Name: insight-ui-webmcp
Version: 0.1.0
Summary: Bring agent-ready website capabilities to Insight UI with WebMCP
Project-URL: Homepage, https://github.com/alpininsight/insight-ui-webmcp
Project-URL: Documentation, https://github.com/alpininsight/insight-ui-webmcp#readme
Project-URL: Issues, https://github.com/alpininsight/insight-ui-webmcp/issues
Author: Alpin Insight Solutions GmbH & Co. KG
License-Expression: Apache-2.0
License-File: LICENSE
License-File: NOTICE
Classifier: Development Status :: 3 - Alpha
Classifier: Framework :: Django
Classifier: Framework :: Django :: 6.0
Classifier: Programming Language :: Python :: 3.12
Classifier: Programming Language :: Python :: 3.13
Classifier: Programming Language :: Python :: 3.14
Requires-Python: >=3.12
Requires-Dist: ais-webmcp<0.2,>=0.1.0
Requires-Dist: django<7,>=6.0.4
Provides-Extra: ui
Requires-Dist: insight-ui<2,>=1.15.0; extra == 'ui'
Description-Content-Type: text/markdown

# Insight UI WebMCP — make your website agent-ready

Bring WebMCP to your Django website with an extension designed for Insight UI.
Expose public content, navigation and reviewed actions as explicit tools, while
your application keeps control of content, permissions and execution.

**DE:** Die WebMCP-Erweiterung für Insight UI: Machen Sie die Inhalte und Aktionen
Ihrer Django-Webseite für KI-Agenten verständlich und gezielt nutzbar.

## Packages at a glance

One browser runtime, register.js from the ais-webmcp core, delivered three ways;
this package is the Django adapter and uses the installed core instead of
shipping its own copy.

```mermaid
flowchart LR
  Core["ais-webmcp (PyPI)<br/>manifest, CLI, register.js"]
  Django["insight-ui-webmcp (PyPI)<br/>Django adapter"]
  NPM["@alpininsightsolutions/webmcp (npm)<br/>register.js only"]
  CDN["cdn.alpininsight.ai/ais-webmcp/vX.Y.Z/<br/>register.js"]
  Core --> Django
  Core --> NPM
  Core --> CDN
  Django --> S1["Django sites"]
  NPM --> S2["other websites (bundlers)"]
  CDN --> S3["script tag"]
```

The npm package `@alpininsightsolutions/webmcp` and the CDN are pending first
release. The [ais-webmcp core](https://github.com/alpininsight/ais-webmcp)
owns register.js. The unscoped npm package `webmcp` is unrelated.

```bash
uv add insight-ui-webmcp
uv run python manage.py webmcp_prepare --profile webpage --dry-run
uv run python manage.py webmcp_prepare --profile webpage
uv run python manage.py webmcp_validate webmcp.manifest.json
```

Add `insight_ui_webmcp` to `INSTALLED_APPS`, then load `{% webmcp_assets %}` from
`webmcp_tags` once in your site shell. The tag emits the helper only. It adds
`<meta http-equiv="origin-trial">` only when `WEBMCP_ORIGIN_TRIAL_TOKEN` is set,
and status never prints that value. In the page, `InsightUiWebmcp.status()`
reports `ok`, `no-origin-trial-meta` or `no-model-context`. Commit the host manifest; `webmcp_prepare`
keeps an existing file unless `--force` is passed. `subscribe_newsletter` is
written `enabled: false` and this package does not register a submit handler.
Explicit host profiles bind the shared manifest to your own content and handlers.
Read-only `webpage` tools declare an `outputSchema` (a JSON Schema object beside
`inputSchema`) so an agent can see the return value. See [Output schemas](#output-schemas).
Local staticfiles are the default; CDN use requires an immutable matching version
and your host's CSP approval.

## Settings

| Setting | Default | Effect |
|---|---|---|
| `WEBMCP_ENABLED` | `False` (host switch) | Hosts set it; `{% webmcp_attribution %}` renders only when it is `True` |
| `WEBMCP_ATTRIBUTION` | `True` | Visible attribution notice; `False` turns it off |
| `WEBMCP_ORIGIN_TRIAL_TOKEN` | unset | Emits the origin-trial meta tag; never printed by status |
| `WEBMCP_ASSET_MODE` | `"local"` | `"cdn"` requires `WEBMCP_CDN_VERSION` matching the installed `ais-webmcp` core |
| `WEBMCP_PROFILES` | `()` | Dotted host profile classes |

`{% webmcp_attribution %}` renders a small `<small>` element,
`Insight UI WebMCP · Apache-2.0 · © Alpin Insight Solutions GmbH & Co. KG`, linking
to alpininsight.ai. It has no script and no inline style; place it in your
footer and style it with `css_class="..."`. To turn it off for one template, use
`{% webmcp_attribution show=False %}`. We are a startup, and we appreciate it if
you keep the notice, which costs you nothing and stays out of the way. It is
optional and can be switched off. Redistribution requirements for
[LICENSE](LICENSE) and [NOTICE](NOTICE) remain separate; see Apache-2.0 section 4.

Python 3.12+, Django 6.0.4–6.x. Insight UI is an optional `ui` extra: existing
websites retain their own Core pin. The framework-independent `ais-webmcp`
command is included as a dependency, with no private host requirements.

The framework-independent [ais-webmcp core](https://github.com/alpininsight/ais-webmcp)
owns the shared schema and browser runtime. This repository contains the Django
adapter and has its own version; it exposes the installed Core asset without
copying it into the adapter distribution.

## Output schemas

`outputSchema` is optional on each tool. It is a JSON Schema object (Draft
2020-12), the same kind of object as `inputSchema`. That is the WebMCP
`ModelContextTool.outputSchema` / MCP `Tool.outputSchema` shape: agents read it
to see what a successful call returns. Leaving the key off means the result
shape is not declared. Read-only tools should set it. This package fills it for
the shipped `webpage` profile, using only values the tool contract already
returns.

| Tool | Declared result |
|---|---|
| `list_sections` | Array of section anchor ids |
| `get_section` | Text of the named section |
| `get_company_pitch` | Short pitch summary (text) |
| `list_products` | At most 12 product cards with `name`, `title`, `status`, and `description` |
| `get_contact` | Public contact details published by the host |

`go_to_section`, `open_legal`, and `start_conversation` do not publish a result
shape here. `subscribe_newsletter` stays `enabled: false` and has no output schema.

`webmcp_prepare --profile webpage` writes these schemas. A schema already stored
on a tool is kept. Any other profile is written unchanged.

`{% webmcp_assets %}` serves the installed Core `register.js` byte-for-byte.
Core validates declared output schemas and forwards them to
`document.modelContext.registerTool`. The adapter adds no validator monkey patch,
startup hook, copied runtime, or browser bridge. Standalone `ais-webmcp validate`
and `ais-webmcp doctor` accept the generated manifests without importing Django
or this adapter first.

The adapter installs the released Core from PyPI (`ais-webmcp>=0.1.0,<0.2`).
The development lock resolves Core `0.1.0`, released from
`5832024dc2f4d4014b7f627d12036bf15bf95992`; no private Git override is needed.
The shared negative-test corpus records that release in
`tests/fixtures/core-provenance.json`. CDN delivery remains separate.

### Host tools (insight-ui-docs and others)

A host declares the schema on its own tool in the committed manifest, or on the
dict returned by `build_manifest().to_dict()`. `webmcp_prepare` does not invent
one for a custom profile. Use `set_output_schema` or set the key directly, and
include only values the handler returns:

```python
from insight_ui_webmcp.output_schemas import set_output_schema

tool = set_output_schema(
    {
        "id": "search_components",
        "name": "Search components",
        "description": "Search public components.",
        "inputSchema": {"type": "object", "properties": {}},
        "annotations": {"readOnlyHint": True},
    },
    {"description": "JSON Schema for the value this handler returns."},
)
```

The same object in a committed `webmcp.manifest.json`:

```json
{
  "id": "search_components",
  "name": "Search components",
  "description": "Search public components.",
  "inputSchema": {"type": "object", "properties": {}},
  "outputSchema": {
    "description": "JSON Schema for the value this handler returns."
  },
  "annotations": {"readOnlyHint": true}
}
```

## Staticfiles configuration

Add the Core finder to your host's existing `STATICFILES_FINDERS`. For hosts
using Django's default finders:

```python
from django.conf.global_settings import STATICFILES_FINDERS as DEFAULT_FINDERS

STATICFILES_FINDERS = [
    *DEFAULT_FINDERS,
    "insight_ui_webmcp.finders.CoreRuntimeFinder",
]
```

Keep any host-specific finders in the list. `collectstatic` continues to expose
`insight_ui_webmcp/js/register.js`, including hashed production filenames.
The finder reads the installed `ais-webmcp` package. CDN mode pins its version
at `https://cdn.alpininsight.ai/ais-webmcp/vX.Y.Z/register.js`.

## Development and release

```bash
uv sync --locked --all-groups
uv run --locked python -m django check --settings=tests.settings
uv run --locked pytest
uv run --locked pre-commit run --all-files
```

The adapter installs the stable compatible Core from PyPI. Core and adapter
versions are independent. CI event routing and the two-stage central package
producer/publication contract are documented in [CI and release evidence](docs/ci-and-release.md).

Split implementation and independent release/host gates:
[issue #63](https://github.com/alpininsight/insight-ui-webmcp/issues/63).
Development preview; public release and native-browser activation remain separate.

The private integration [documentation map](https://github.com/alpininsight/insight-ui-webmcp-docs/blob/develop/README.md)
and [guide](https://github.com/alpininsight/insight-ui-webmcp-docs/blob/develop/docs/guide/README.md)
cover both repositories. Cloudflare's optional edge integration complements
origin registration and does not replace it
([details](https://github.com/alpininsight/insight-ui-webmcp-docs/blob/develop/docs/reference/cloudflare-edge.md)).


### Debug staticfiles compatibility

`CoreRuntimeFinder.list()` accepts the optional `None` ignore-pattern value as
well as collectstatic's list. Post-merge audit of #64: installed-distribution
and production collectstatic checks passed, but debug asset discovery exercised
this untested input and raised TypeError. Regression probes cover both caller
forms and assert that enumeration still exposes only installed Core bytes.
When adding finders, verify debug discovery as well as production collection;
a successful container build covers only the latter runtime configuration.
