MCP Sigil Resolver Server

MCP Sigil Resolver Server – Design Proposal

Background

Sigils are currently resolved inside the Django application through core.sigil_resolver, which inspects the SigilRoot configuration, looks up model instances, and falls back to a gway subprocess for unknown roots. The resolver supports nested sigils, dynamic model lookups, environment variables, and per-thread context provided through core.sigil_context. Sigil metadata is surfaced in the admin via the Sigil Builder view, which lists known roots and lets administrators experiment with resolution.

The product roadmap calls for exposing the same capabilities outside of Django via OpenAI's Model Context Protocol (MCP) so connectors can resolve sigils over SSE.

Goals

Non-Goals

Protocol Surface

The server will expose the following MCP constructs:

Type Name Purpose
Tool resolveSigils Resolve one or more sigils inside a text payload using the current session context. Input schema: { "text": string, "context": {"model": {"app_label.ModelName": "pk"}}, "options": {"skipUnknown": bool}}. Returns { "resolved": string, "metadata": {"unresolved": [string]}}.
Tool resolveSingle Resolve a single sigil token and return its value or unresolved form. Thin wrapper that validates the sigil shape before delegating to resolveSigils for reuse.
Tool describeSigilRoot Provide metadata for a given sigil root (fields, context type) leveraging the same data that powers the Sigil Builder view.
Tool setContext Update the thread-local sigil context using set_context to mimic how the resolver infers instances from request state.
Resource sigilRoots (optional streaming) Publish changes to SigilRoot objects so long-lived MCP sessions can react to new roots without polling. Implemented via Django signals.

The server’s list_tools handler simply advertises the tools above, while call_tool dispatches to a per-session service class that wraps resolve_sigils and _resolve_token logic so every invocation reuses the battle-tested paths.

Server Architecture

manage.py mcp_sigil_server
└── SigilResolverServer (mcp.server.sse.SseServer)
    ├── SigilSessionState (per-connection context)
    │   └── SigilContextAdapter ↔ core.sigil_context
    ├── SigilResolverService
    │   └── uses core.sigil_resolver.resolve_sigils
    └── SigilRootCatalog (queries SigilRoot + caches metadata)

Configuration & Security

Implementation Plan

  1. Foundations
    • Add the dependency and create core/mcp/__init__.py, core/mcp/server.py, and core/mcp/schemas.py with Pydantic models to validate tool arguments before passing them to Django.
    • Implement SigilResolverService that exposes resolve_text, resolve_single, set_context, and describe_root. It should call resolve_sigils and interact with SigilRoot directly.
  2. MCP server
    • Wire the service into an SseServer inside the management command. Handle lifecycle events (session start/end) to clear context using clear_context to prevent leaks.
    • Expose the tools and resources by implementing the relevant decorators from the MCP SDK.
  3. Admin & Ops
    • Document how to create API keys and register the connector. Provide example curl traces to validate the SSE handshake.
    • Extend deployment scripts (e.g., start.sh or a systemd unit) so the MCP server can run alongside Django in production.
  4. Testing
    • Unit-test the service class against fixtures already used by tests/test_sigil_resolution.py to ensure parity with in-process resolution.
    • Add an async integration test that spins up the SSE server on an ephemeral port, runs through list_tools and call_tool, and verifies resolution and authorization behavior.
    • Reuse existing factories to assert context-aware lookups (e.g., entity sigils with filter_field rules).

Operational Considerations

Future Enhancements