Self-hosted UCP server: generate Universal Context Packages from GitHub/Jira over REST and MCP (Streamable HTTP). One command to run.
Project description
ucp-server — self-hosted UCP generation service
One process, two interfaces. Point it at GitHub/Jira credentials and get Universal Context Packages on demand:
- REST API (
/v1) — generate and fetch packages withcurlor any HTTP client; - MCP over Streamable HTTP (
/mcp) — plug it straight into Cursor, Claude Code, or any MCP-capable agent.
Configuration is environment-only (12-factor), generated packages are cached on disk with a TTL, and authentication is one env var away. Install it, start it, forget it.
PyPI package name:
ucpcore-server(the nameucp-serverwas taken). The command it installs is stillucp-server.
Quickstart
Docker (one command)
docker run --rm -p 8080:8080 -e GITHUB_TOKEN=ghp_yourtoken \
ghcr.io/ucpcore/ucp-server:latest
uvx / pipx (no Docker)
uvx --from ucpcore-server ucp-server
# or: pipx run --spec ucpcore-server ucp-server
Then generate a package from any public GitHub issue:
curl -s -X POST http://localhost:8080/v1/generate \
-H 'Content-Type: application/json' \
-d '{"source": "github", "ref": "pallets/flask#5961"}' | head
Interactive API docs: http://localhost:8080/docs.
Connect an agent (MCP)
The MCP endpoint speaks Streamable HTTP at http://localhost:8080/mcp.
Cursor / Claude Code (mcp.json):
{
"mcpServers": {
"ucp": {
"url": "http://localhost:8080/mcp"
}
}
}
If the server runs with UCP_SERVER_API_KEY, add the header:
{
"mcpServers": {
"ucp": {
"url": "http://localhost:8080/mcp",
"headers": { "Authorization": "Bearer YOUR_KEY" }
}
}
}
Tools exposed:
| Tool | Purpose |
|---|---|
generate_context(source, ref, llm=False) |
Build a UCP from a GitHub issue (owner/repo#123) or Jira ticket (PROJ-123) |
list_contexts() |
List cached packages: id, entity, title, freshness |
get_context(id) |
Full UCP JSON for a cached package |
get_context_markdown(id, token_budget?) |
Canonical Markdown rendering (SPEC §7), optionally truncated by salience |
REST API
| Method & path | Purpose |
|---|---|
POST /v1/generate |
Generate a package. Body: {"source": "github"|"jira", "ref": "...", "llm": false, "since": null, "audience": null}. Returns the UCP JSON; headers X-UCP-Package-Id and X-UCP-Cache: hit|miss. |
GET /v1/packages |
Cached packages: id, title, entity, generated_at |
GET /v1/packages/{id} |
Full UCP JSON |
GET /v1/packages/{id}/markdown?token_budget=1500 |
Canonical Markdown rendering |
GET /healthz, GET /readyz |
Liveness / readiness probes (never authenticated) |
GET /docs, GET /openapi.json |
OpenAPI documentation |
Errors are RFC 9457 problem documents (application/problem+json):
{"type": "https://ucpcore.org/problems/invalid-ref", "title": "Invalid Reference",
"status": 400, "detail": "invalid GitHub reference 'x': expected owner/repo#number..."}
Examples:
# Jira (needs JIRA_* env on the server)
curl -s -X POST http://localhost:8080/v1/generate \
-H 'Content-Type: application/json' \
-d '{"source": "jira", "ref": "PROJ-123"}'
# LLM-enhanced (needs UCP_LLM_* env on the server)
curl -s -X POST http://localhost:8080/v1/generate \
-H 'Content-Type: application/json' \
-d '{"source": "github", "ref": "microsoft/vscode#519", "llm": true}'
# Rendered Markdown under a token budget
curl -s "http://localhost:8080/v1/packages/github-pallets-flask-5961/markdown?token_budget=1500"
Configuration
Everything is optional; the server starts with zero configuration and reports clearly when a credential is missing for a requested source.
| Variable | Default | Purpose |
|---|---|---|
UCP_SERVER_HOST |
127.0.0.1 (Docker image: 0.0.0.0) |
Bind address |
UCP_SERVER_PORT |
8080 |
Bind port |
UCP_SERVER_API_KEY |
(unset — auth disabled) | When set, all endpoints except health probes require Authorization: Bearer <key> |
UCP_CACHE_DIR |
~/.cache/ucp-server |
Disk cache for generated packages |
UCP_CACHE_TTL |
900 (15 min) |
Cache TTL in seconds; 0 disables caching |
GITHUB_TOKEN / GH_TOKEN |
(unset) | GitHub token (public issues work without it, at a low rate limit) |
JIRA_BASE_URL |
(unset) | e.g. https://yourcompany.atlassian.net |
JIRA_EMAIL |
(unset) | Jira Cloud email (Basic auth); omit for Server/DC PAT |
JIRA_API_TOKEN |
(unset) | Jira API token or PAT |
UCP_LLM_BASE_URL |
https://api.openai.com/v1 |
OpenAI-compatible endpoint for llm: true |
UCP_LLM_API_KEY |
(unset) | LLM API key (falls back to OPENAI_API_KEY) |
UCP_LLM_MODEL |
gpt-4o-mini |
LLM model name |
UCP_LOG_JSON |
false |
1/true switches to JSON-lines logs |
UCP_LOG_LEVEL |
INFO |
Log level |
Security
- Set
UCP_SERVER_API_KEYfor any non-localhost deployment. Without it anyone who can reach the port can spend your GitHub/Jira/LLM quota. The key is compared in constant time; health probes stay open for orchestrators. - Bind is
127.0.0.1by default when run directly. The Docker image setsUCP_SERVER_HOST=0.0.0.0deliberately — the container boundary is the isolation there; publish the port consciously (-p 127.0.0.1:8080:8080keeps it local). - No client-supplied URLs. Clients pass references (
owner/repo#123,PROJ-123) to the two predefined connectors; the server never fetches an arbitrary URL on a client's behalf (no SSRF surface). - Request bodies are limited to 64 KiB and validated strictly (unknown fields rejected). Tokens are masked in logs. The Docker image runs as a non-root user.
Development
python3 -m venv .venv && . .venv/bin/activate
pip install -e ".[dev]"
pytest
Docker image:
docker build -t ucp-server .
docker run --rm -p 8080:8080 ucp-server
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file ucpcore_server-0.1.0.tar.gz.
File metadata
- Download URL: ucpcore_server-0.1.0.tar.gz
- Upload date:
- Size: 16.6 kB
- Tags: Source
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.12
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
88cef0319d42f49aebdb6a9f700012fb39d44dbba16e0d3ae59c6b36cdf29a16
|
|
| MD5 |
373e5199a761fd23ccd7ee3d95d5ef9c
|
|
| BLAKE2b-256 |
e05ba57d914b2a44a8e4f43ad4a9e28939f7dd3bcbae56ac84cd87e6820a38ac
|
Provenance
The following attestation bundles were made for ucpcore_server-0.1.0.tar.gz:
Publisher:
release.yml on ucpcore/ucp
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
ucpcore_server-0.1.0.tar.gz -
Subject digest:
88cef0319d42f49aebdb6a9f700012fb39d44dbba16e0d3ae59c6b36cdf29a16 - Sigstore transparency entry: 2082697789
- Sigstore integration time:
-
Permalink:
ucpcore/ucp@c9cfe9127cb8c726eda1939fc02a850102cfabf5 -
Branch / Tag:
refs/tags/server-v0.1.0 - Owner: https://github.com/ucpcore
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
release.yml@c9cfe9127cb8c726eda1939fc02a850102cfabf5 -
Trigger Event:
push
-
Statement type:
File details
Details for the file ucpcore_server-0.1.0-py3-none-any.whl.
File metadata
- Download URL: ucpcore_server-0.1.0-py3-none-any.whl
- Upload date:
- Size: 15.3 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.12
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
05f739fad9e87cffbb6598cfed07aba841388d42e8d5858bab40b860d7317c7e
|
|
| MD5 |
bcd704e2082f914fc2fae09d9d26bf18
|
|
| BLAKE2b-256 |
e5d9f6bb3220ab379ee13363a9f88b08d2af6a3385bba40c559a1e45a12b81af
|
Provenance
The following attestation bundles were made for ucpcore_server-0.1.0-py3-none-any.whl:
Publisher:
release.yml on ucpcore/ucp
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
ucpcore_server-0.1.0-py3-none-any.whl -
Subject digest:
05f739fad9e87cffbb6598cfed07aba841388d42e8d5858bab40b860d7317c7e - Sigstore transparency entry: 2082697791
- Sigstore integration time:
-
Permalink:
ucpcore/ucp@c9cfe9127cb8c726eda1939fc02a850102cfabf5 -
Branch / Tag:
refs/tags/server-v0.1.0 - Owner: https://github.com/ucpcore
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
release.yml@c9cfe9127cb8c726eda1939fc02a850102cfabf5 -
Trigger Event:
push
-
Statement type: