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.1.0 — connectors can now emit all three MCP primitives. Beyond tools (reads + gated actions), use
@mcp_resourceto expose URI-addressable resources (static or templated) and@promptto offer prompt templates. See the Resources & Prompts guide and CHANGELOG.md. Built on v1.0.0 — all four build phases below remain.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
deepqueryCLI and mock-agent harness with the §5/§6/§13 contracts encoded asvalidatechecks (Phase 3), and the semver compatibility contract + packaging (Phase 4). The SDK contract is at major version 1: connectors declaringsdk_major_version = 1are 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
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 deepquery_sdk-1.1.1.tar.gz.
File metadata
- Download URL: deepquery_sdk-1.1.1.tar.gz
- Upload date:
- Size: 51.5 kB
- Tags: Source
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.2.0 CPython/3.13.3
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
f532df203f967284f2f46373a99b23166ec3e3954bac6995f51b937c9f2137d1
|
|
| MD5 |
a17d3674664464f5b057fa351d48f4ad
|
|
| BLAKE2b-256 |
b23fea700fe71339ebd83fa574b87babc8f86b04150c295d79b25adad58f0007
|
File details
Details for the file deepquery_sdk-1.1.1-py3-none-any.whl.
File metadata
- Download URL: deepquery_sdk-1.1.1-py3-none-any.whl
- Upload date:
- Size: 48.7 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.2.0 CPython/3.13.3
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
2254f9edd78b67a8a444262019606a80c3800972b47603aa1a6ac42dfbf0d432
|
|
| MD5 |
dcb90df62fa64d473ef06126b4f705f2
|
|
| BLAKE2b-256 |
42891577707bf91d107a432eaa36a27afbd11bfec11524df40d39d6795c37ea2
|