Skip to content

v0.4.0

Latest

Choose a tag to compare

@kinjelom kinjelom released this 27 Sep 08:56
· 1 commit to main since this release

Added

  • Prometheus metrics: what the site and the MCP server are asked for.
    Which pages people read (mkdocsgo_site_page_views_total), which tools
    agents call and how the calls end, which pages those tools hand out, how
    many searches found nothing, and requests, latency and bytes by route and
    zone. Every label value comes from a closed set - a page in the build, a
    registered tool, a configured zone - never from a request path or a search
    query, so a scanner cannot mint series. Off unless asked for.

  • -metrics-addr serves /metrics on a listener of its own, never on the
    published -http address.

  • -metrics-push sends the metrics to a Pushgateway - or VictoriaMetrics - every
    -metrics-push-interval, grouped by -metrics-job and -metrics-instance,
    and deletes the group on shutdown. The URL may carry Basic credentials and is
    read from MKDOCSGO_METRICS_PUSH_URL when the flag is absent, so they stay out
    of the process list. This is how metrics leave a Cloud Foundry instance.

  • -metrics-users name|hash labels the metrics that say who read what with
    the principal behind the request - on the site, and inside MCP tool calls,
    where the identity from the zone check reaches the tools per request. hash
    is a 12-character pseudonym, keyed by MKDOCSGO_METRICS_USER_SALT when set;
    unsalted, it can be recomputed from the names in mkdocsgo.yml, and the
    startup log says so. Off by default.

  • METRICS.md: the metrics, both ways out, and the queries worth having.

  • Markdown sources on the site, per zone. A zone with markdown: true
    serves each page's Markdown at the page's address with .md added -
    /guides/deploy/ as /guides/deploy.md - and at its path under docs_dir.
    On a Material site each page gets a download button among Material's page
    actions, and every page gets a <link rel="alternate" type="text/markdown">
    for agents that read HTML. A browser is sent text/plain, so it shows the
    source instead of saving it. Only pages MkDocs built are offered, the source
    is as protected as its page, and every other zone is served exactly what
    MkDocs wrote. markdown: true on a zone that is off stops the start.

  • ?section=<anchor> on any of those addresses returns one section - the
    heading and the text beneath it - which is what get_section returns, from
    the same code. For an agent that fetches URLs rather than speaking MCP, the
    cheap way to read stays cheap. An unknown anchor is a 404 that lists the
    ones the page has.

  • OAuth sign-in for MCP clients, so claude.ai can connect. claude.ai,
    Claude Desktop and Claude mobile add a remote server by its URL and nothing
    else, so a static token was no way in for them. A zone with oauth: true now
    runs an OAuth 2.1 authorization server inside the binary: RFC 8414 metadata,
    dynamic client registration (RFC 7591), the authorization code flow with
    PKCE (S256 only), and refresh. The person signing in is one of the zone's
    principals, with the password already in mkdocsgo.yml. Claude Code signs
    in the same way, through a loopback redirect on any port, and static tokens
    keep working beside it.

  • Nothing is stored. Client registrations, codes, access and refresh tokens
    are sealed with an HMAC under MKDOCSGO_OAUTH_KEY, the one secret, which
    lives in the environment rather than in the file. Any instance accepts what
    another issued and a restart signs nobody out. Taking a principal out of the
    zone or changing its password, then restarting, signs out every client it
    signed in; changing the key signs out everyone.

  • oauth.redirect_uris is the allowlist a client registration may name,
    defaulting to Claude's callback and Claude Code's loopback;
    oauth.access_token_ttl (1 hour) and oauth.refresh_token_ttl (30 days)
    set the lifetimes.

  • docs/adr/0002-built-in-oauth-for-mcp-clients.md: why the authorization
    server is built in and stateless, and what that costs - a secret, no
    per-token revocation, no refresh-token rotation.

Changed

  • Both halves publish the same pages. With a built site loaded
    (-mode site+mcp), the MCP half keeps only the pages MkDocs built a page
    from - the rule the Markdown sources use. A page a plugin excluded is no
    longer searchable and readable through /mcp while missing from the site.
    The startup log lists what was left out.
  • draft_docs is honoured like exclude_docs: mkdocs build leaves drafts
    out, and so does the index, in every mode.
  • The protected resource metadata of a zone with oauth: true names its
    authorization server in authorization_servers.
  • A bearer token presented and refused on /mcp gets error="invalid_token"
    in the WWW-Authenticate challenge, which tells an OAuth client to refresh
    rather than start over.
  • A zone with oauth: true served over HTTP with /mcp will not start without
    MKDOCSGO_OAUTH_KEY, 32 characters or more.