Skip to content

Latest commit

 

History

4 Commits

Folders and files

NameName
Last commit message
Last commit date
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

SourceryKit × Skilder Integration Examples

Two runnable demos showing how to embed SourceryKit's interception and verification layer into an MCP tool, connect it to Skilder, and run AI agents that produce cryptographically verifiable claims.

What This Repo Shows

  • A custom MCP server (mcp/server.py) that wraps an HTTP call with SourceryKit's async_intercept_context, storing every outbound request in a verifiable database. The server runs externally and is connected to Skilder via Streamable HTTP.
  • Two agent demos that call the tool via Skilder, extract claims from the response, and run SourceryKit's handoff evaluation to verify those claims against the source of truth.

Architecture

flowchart TD
    Agent["AI Agent\n(any MCP client)"]
    Skilder["Skilder\nSkills → Tools"]
    MCP["External MCP Server\n(SourceryKit)"]
    API["External API\n(Open-Meteo)"]
    DB[("SourceryKit\nIntercepts DB")]
    Response["Agent Response\n(answer + claims + ref)"]
    Payload["Handoff Payload\n(claims + ref)"]
    Eval["SourceryKit\nEvaluator"]
    Provably["Provably Backend\n(proof verify)"]

    Agent -->|"1. calls tool"| Skilder
    Skilder -->|"2. routes"| MCP
    MCP -->|"3. HTTP call"| API
    API -.->|"response"| MCP
    MCP -->|"4. stores tool output"| DB
    DB -.->|"returns ref"| MCP
    MCP -->|"5. returns data + ref"| Response
    Response -->|"6. build_handoff_payload"| Payload
    Payload -->|"7. evaluate"| Eval
    Eval <-->|"9. proof verify"| Provably
    Provably -.->|"8. query records"| DB
    Eval -->|"10. PASS / CAUGHT"| Result{{"PASS / CAUGHT"}}
Loading
  1. Agent calls a tool through Skilder
  2. Skilder routes the call to the external MCP server
  3. MCP server makes the HTTP call to the External API
  4. MCP server stores the tool output (request + response) in the SourceryKit Intercepts DB, returns data + sourcerykit_ref
  5. MCP server returns data + ref to the agent
  6. Agent returns SourceryKitAgentResponse (answer + claims with ref)
  7. build_handoff_payload bundles claims with intercept metadata
  8. Provably backend queries the Intercepts DB to retrieve the recorded tool output
  9. Provably backend verifies the cryptographic proof
  10. SourceryKit locally compares claimed values against proof-verified results
  11. Returns PASS or CAUGHT

Prerequisites

  • Python 3.12+
  • A SourceryKit account with database access
  • A Skilder workspace
  • An LLM API key for your chosen agent framework
  • Your MCP server must be publicly accessible via a Streamable HTTP URL (or reachable from Skilder's cloud)

Setup

1. Configure SourceryKit

pip install sourcerykit
sourcerykit init

The interactive wizard handles account creation/login, organization selection, PostgreSQL database linking, project naming, and bootstrapping (DB tables, Provably handshake, saving IDs to .env).

Important: The MCP server and the local demo must use the same PROVABLY_API_KEY and SOURCERYKIT_ORG_ID. After running sourcerykit init, the values are stored in:

  • Global config (API key + org ID):
    • macOS: ~/Library/Application Support/sourcerykit/config.json
    • Linux: ~/.config/sourcerykit/config.json
  • Local .env (bootstrap IDs, postgres URL): in your project directory

Ensure the MCP server's environment uses the same values.

2. MCP Server

The MCP server in this example is hosted externally on GCP and is accessible at:

https://mcp-weather.provably.ai/sse

For your own deployment, see the mcp/server.py for reference.

3. Register in Skilder & Create Skill/Role

  1. Add the MCP server — In Skilder, go to Library → Tools → Add Tools → Add a custom server. Enter the Streamable HTTP URL of your externally-hosted MCP server (e.g. https://mcp-weather.provably.ai/sse). Save and verify the server status is Connected.

  2. Create a skill — Go to Library -> Skills → New Skill. Name it, add instructions describing what the agent should do, and select the tools from your registered MCP server. Save.

  3. Create a role — Go to Roles → New Role. Name it and assign the skill you just created. Create the role.

Your agent can now discover and use the tool when connected to this role. See the Skilder docs for the full walkthrough.

Running the Demos

Configure the root .env with your LLM credentials. Each script has its own requirements — check the comments at the top of the file.

# For Claude demo
MODEL_NAME=claude-haiku-4-5
ANTHROPIC_API_KEY=<YOUR_ANTHROPIC_KEY>

# For OpenAI demo
OPENAI_MODEL_NAME=openai/gpt-5-nano
MODEL_URL=http://127.0.0.1:1234/v1
MODEL_API_KEY=<YOUR_MODEL_KEY>

# Skilder connection
SKILDER_USER_KEY=<YOUR_SKILDER_USER_KEY>
SKILDER_WORKSPACE_ID=<YOUR_SKILDER_WORKSPACE_ID>

Run an Example

This repo includes two demo scripts:

python claude_agent_run_skilder.py     # Claude Agents SDK
python openai_agent_run_skilder.py     # OpenAI Agents SDK

Both demos follow the same flow: a primary orchestrator delegates to a weather specialist subagent, which calls the Skilder-hosted tool, extracts claims, and runs SourceryKit's handoff evaluation.

SourceryKit supports other frameworks too — see the cookbooks for LangChain, LangGraph, CrewAI, and more.

How the Integration Works

The integration has three layers: an MCP server that intercepts HTTP calls and logs them to a database, agents that use tool output and return structured answers with extracted claims, and a verification step that compares claims against the source of truth.

1. External MCP Server: Intercept + Audit

The MCP server runs independently (e.g. on GCP) and is connected to Skilder via Streamable HTTP. SourceryKit patches the HTTP library process-wide, logs the request/response to the intercepts table of a verifiable database, and returns a ref UUID that links the network traffic to this specific call.

Bootstrap at startup — on the external server, register trusted destinations and initialize the interceptor (mcp/server.py:49-56):

await sourcerykit.bootstrap_system()
await sourcerykit.insert_trusted_endpoint(url=_OPEN_METEO_BASE_URL)

Intercept the outbound call — wrap the HTTP request and return the ref alongside the data (mcp/server.py:22-46):

@mcp.tool(
    name="get_current_temperature_london",
    description="Fetch current temperature for London with SourceryKit intercept context",
)
async def get_current_temperature_london() -> dict[str, Any]:
    async with sourcerykit.async_intercept_context(
        agent_id=os.getenv("SOURCERYKIT_AGENT_ID", "mcp-demo"),
        action_name="get_weather",
    ) as ref:
        async with httpx.AsyncClient() as client:
            response = await client.get(
                _OPEN_METEO_BASE_URL,
                params={
                    "latitude": 51.5074,
                    "longitude": -0.1278,
                    "current": "temperature_2m",
                },
                timeout=30,
            )
            data = response.json()

    return {
        "content": [
            {
                "type": "text",
                "text": json.dumps({**data, "sourcerykit_ref": ref}),
            }
        ]
    }

The agent must receive the sourcerykit_ref — it's the key that binds the agent's claims back to the raw intercepted data.

2. Agent: Structured Claims via SourceryKitAgentResponse

Agents must return a typed response with answer and claimed_values. Each claimed value points to a field in the tool output via JSONPath and carries the sourcerykit_ref from the tool call.

The schema (sourcerykit/schemas/agent_response.py):

class ClaimedValue(BaseModel):
    path: str          # JSONPath into tool output, e.g. "$.current.temperature_2m"
    value: str         # Extracted value as string
    sourcerykit_ref: str  # Must match the ref from the tool call

class SourceryKitAgentResponse(BaseModel):
    answer: str                           # Human-readable explanation
    claimed_values: list[ClaimedValue]    # Extracted claims to verify

The pattern is the same across frameworks — enforce SourceryKitAgentResponse as the agent's structured output. Here are two examples:

OpenAI Agents SDK — pass as output_type (openai_agent_run_skilder.py:121-127):

weather_specialist_agent = Agent(
    name="london_weather_specialist",
    instructions=subagent_instructions,
    mcp_servers=[skilder_mcp],
    model=_DEFAULT_MODEL,
    output_type=SourceryKitAgentResponse,
)

Claude Agents SDK — pass the JSON schema via output_format (claude_agent_run_skilder.py:42-74):

schema_str = json.dumps(SourceryKitAgentResponse.model_json_schema(), indent=2)

options = ClaudeAgentOptions(
    system_prompt="You are a primary orchestrator...",
    mcp_servers={"skilder": {"type": "http", "url": "<YOUR_SKILDER_MCP_URL>"}},
    agents={
        "london_weather_specialist": AgentDefinition(
            description="Skilder London Weather Bot.",
            prompt=(
                "Your output MUST be a raw JSON object strictly adhering to this schema:\n"
                f"{schema_str}\n\n"
                "Do NOT alter, rename, or drop key names (such as 'sourcerykit_ref')."
            ),
            mcpServers=["skilder"],
            tools=["mcp__skilder__*"],
        )
    },
    model=_DEFAULT_MODEL,
    output_format={
        "type": "json_schema",
        "schema": SourceryKitAgentResponse.model_json_schema(),
    },
)

See the cookbooks for LangChain, LangGraph, CrewAI, and other framework integrations.

3. Verification: Handoff + Evaluation

After the agent responds, two steps verify the claims:

Build the handoff payload — bundle claims with intercept metadata (claude_agent_run_skilder.py:105-119):

payload = await build_handoff_payload(
    {
        "answer": final_output.answer,
        "claims": [
            {
                "action_name": "get_weather",
                "claimed_value": final_output.claimed_values,
                "verification_mode": "field_extraction",
            }
        ],
    },
    run_id=uuid.uuid4(),
    prompt=prompt,
    intercept_agent_id="demo",
)

Evaluate — send to Provably backend, which verifies the cryptographic proof against the intercepted HTTP records (claude_agent_run_skilder.py:122-125):

eval_result = await evaluate_handoff(payload=payload)
# eval_result["outcome"] → "PASS" | "CAUGHT" | "ERROR"
print(json.dumps(eval_result, indent=2))

The backend verify the cryptographic proof. SourceryKit then locally compares the agent's claimed values against the proof-verified results — matching values return PASS, mismatches return CAUGHT.

Possible Integrations

1. Skilder Logs as Source of Truth

Skilder's monitoring captures every tool call with full request/response payloads. This can serve as the verifiable audit trail instead of SourceryKit's own PostgreSQL intercepts table. In this setup, the sourcerykit_ref in the agent's claims maps to Skilder's log entry for the tool call.

2. Output Schema in Skilder Skills

A Skilder skill can embed SourceryKit's SourceryKitAgentResponse schema in its references or scripts, instructing the agent to return structured claims. The skill's script can also run build_handoff_payload from the agent's output, packaging the claims into a ready-to-evaluate payload. The agent follows the skill's instructions without needing to know SourceryKit internals.

Links

About

No description, website, or topics provided.

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages