Skip to main content

Connector Development Kit for Deep Query — build MCP-emitting connectors with built-in read/action safety classification and provenance.

Project description

DeepQuerySDK — Connector Development Kit

Build connectors for Deep Query. A connector you write with this SDK emits a standard Model Context Protocol (MCP) server — so Deep Query consumes it through the exact same interface as any public MCP server. You never touch JSON-RPC, transport, or schema plumbing.

Status: v1.0.0 — all four build phases complete. Core contracts (Phase 1), the gated preview → approve → execute / reject lifecycle + OAuth 2.1 PKCE scaffolding + credential injection (Phase 2), the deepquery CLI and mock-agent harness with the §5/§6/§13 contracts encoded as validate checks (Phase 3), and the semver compatibility contract + packaging (Phase 4). The SDK contract is at major version 1: connectors declaring sdk_major_version = 1 are loadable by this runtime.

What you define

A connector is a subclass of Connector that declares three things:

You define What it is Gated?
Resources read-only data the agent can retrieve and cite no
Actions operations that change external state yes (preview → execute)
Auth how the connector authenticates to the external system n/a

Every read carries a provenance envelope so live data can be cited honestly. Every action is tagged dq.mutates: true in the emitted MCP server so Deep Query's approval gate knows it must be confirmed by a human.

Install (development)

# from the DeepQuerySDK/ folder, using the bundled venv
venv\Scripts\python.exe -m pip install -e .

60-second example

from deepquery_sdk import Connector, OAuth2Auth, resource, action

class JiraConnector(Connector):
    name = "jira"
    version = "0.1.0"
    description = "Read and act on Jira issues."

    # Declare OAuth 2.1 with least-privilege scopes. The gateway runs/stores the
    # grant and injects the token; this connector never stores credentials.
    auth = OAuth2Auth(
        authorize_endpoint="https://auth.atlassian.com/authorize",
        token_endpoint="https://auth.atlassian.com/oauth/token",
        scopes=["read:jira-work", "write:jira-work"],
    )
    requires_network = True

    @resource(description="Search Jira issues by text query.",
              input_schema={"type": "object",
                            "properties": {"query": {"type": "string"}},
                            "required": ["query"]})
    def search_issues(self, query: str):
        # ... call the real Jira API here ...
        return [
            self.cite(
                {"key": "DQ-431", "summary": "Login flow broken", "status": "In Review"},
                source_object_id="DQ-431",
                title_or_label="DQ-431 — Login flow broken",
                deep_link="https://example.atlassian.net/browse/DQ-431",
                mutability_note="live status field",
            )
        ]

    @action(description="Create a new Jira issue.",
            input_schema={"type": "object",
                          "properties": {"project": {"type": "string"},
                                         "summary": {"type": "string"}},
                          "required": ["project", "summary"]})
    def create_issue(self, project: str, summary: str):
        # only ever called after the approval gate confirms the preview.
        auth = self.apply_auth()  # headers built from the injected credential
        return {"created": f"{project}-NEW", "summary": summary}

    @create_issue.preview
    def _(self, project: str, summary: str) -> str:
        return f"Will create a new issue in project '{project}' titled '{summary}'."

Emit and serve it as an MCP server (the gateway injects the credential):

from deepquery_sdk import Credential, static_credential_provider
from deepquery_sdk.mcp_emit import run_stdio

connector = JiraConnector()
connector.set_credential_provider(static_credential_provider(Credential(token="...")))
run_stdio(connector)

The gated action lifecycle

Calling an action does not execute it. It returns a preview and a single-use approval token; the gateway drives the decision through two control tools:

call create_issue(args)        -> { status: "preview", approval_token, preview, arguments }
call dq.execute_action(token)  -> runs execute() for exactly those args  (after human approval)
call dq.reject_action(token)   -> discards the action; it never runs

The token binds the previewed arguments, so execute can never drift from what the human approved, and a rejected/used token can never run.

The deepquery CLI

deepquery scaffold acme-crm           # generate a new connector from the template
deepquery validate connector.py       # enforce the §5/§6/§13 safety contracts
deepquery manifest connector.py       # print/export the connector manifest
deepquery run-dev connector.py        # drive it interactively with the mock agent
deepquery emit connector.py --out dist/   # produce the deployable MCP server artifact

A target can be a path/to/connector.py, a directory containing connector.py, or a module.path:ClassName. validate is the gatekeeper: it statically scans @resource bodies for mutating calls and fails a resource that writes (a misclassified action), plus checks descriptions, manifest, deployment honesty, and least-privilege scopes.

The dev harness (deepquery_sdk.harness.MockAgent) discovers a connector over a real in-memory MCP session and drives reads (inspecting provenance) and the full preview → approve / reject action flow — the same sequence the real Agent Layer uses.

Try it without the test suite

# read path + classification + provenance, over a real stdio MCP server
venv\Scripts\python.exe examples\manual_client.py

# the full preview -> approve -> execute and preview -> reject flow
venv\Scripts\python.exe examples\manual_action_flow.py

See examples/jira_connector/ for the full runnable connector used in the Phase 1 and Phase 2 tests.

Versioning & compatibility

The SDK follows SemVer; see CHANGELOG.md. Every connector manifest declares the SDK major version it targets, and the gateway calls assert_compatible(manifest) before loading — refusing a connector built against an incompatible major with a clear error. Breaking changes ship with a guide in MIGRATIONS.md.

Release / publishing (maintainers)

Distributions are built with python -m build into dist/. To publish to PyPI:

python -m build                       # build sdist + wheel into dist/
python -m twine check dist/*          # validate metadata
python -m twine upload dist/*         # publish (requires PyPI credentials)

Tag the release v<version> and ensure version in pyproject.toml matches SDK_VERSION (a test enforces this against the installed package).

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

deepquery_sdk-1.0.0.tar.gz (43.9 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

deepquery_sdk-1.0.0-py3-none-any.whl (44.3 kB view details)

Uploaded Python 3

File details

Details for the file deepquery_sdk-1.0.0.tar.gz.

File metadata

  • Download URL: deepquery_sdk-1.0.0.tar.gz
  • Upload date:
  • Size: 43.9 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.2.0 CPython/3.13.3

File hashes

Hashes for deepquery_sdk-1.0.0.tar.gz
Algorithm Hash digest
SHA256 790b896426007d3ef06cea004875702c6ee8c17c50ed3600d204f90a05869094
MD5 f1398a0d401e21fde02e0cee4815c113
BLAKE2b-256 29c1397b8dad231479e4a17e50a7cef145fefd1257447f16ecee3bb8c8f8f61a

See more details on using hashes here.

File details

Details for the file deepquery_sdk-1.0.0-py3-none-any.whl.

File metadata

  • Download URL: deepquery_sdk-1.0.0-py3-none-any.whl
  • Upload date:
  • Size: 44.3 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.2.0 CPython/3.13.3

File hashes

Hashes for deepquery_sdk-1.0.0-py3-none-any.whl
Algorithm Hash digest
SHA256 8451df2111d543b5ad06939a3ddac8c41f74f2a0bf03b0ae8b96ee2a0942ea9c
MD5 705b19a5d26749d2018f560f69a85cc0
BLAKE2b-256 573f8a688335a7f236a3ec56963ab3540f62305e59e56b64161d9237a07ae97c

See more details on using hashes here.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page