vaultkit 0.1.0__tar.gz → 0.2.0__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (42) hide show
  1. {vaultkit-0.1.0 → vaultkit-0.2.0}/PKG-INFO +7 -5
  2. {vaultkit-0.1.0 → vaultkit-0.2.0}/pyproject.toml +11 -4
  3. vaultkit-0.2.0/vaultkit/mcp/__init__.py +32 -0
  4. vaultkit-0.2.0/vaultkit/mcp/__main__.py +116 -0
  5. vaultkit-0.2.0/vaultkit/mcp/identity.py +118 -0
  6. vaultkit-0.2.0/vaultkit/mcp/server.py +130 -0
  7. vaultkit-0.2.0/vaultkit/tools/adapters/mcp.py +41 -0
  8. {vaultkit-0.1.0 → vaultkit-0.2.0}/vaultkit/tools/definitions.py +9 -6
  9. {vaultkit-0.1.0 → vaultkit-0.2.0}/vaultkit.egg-info/PKG-INFO +7 -5
  10. {vaultkit-0.1.0 → vaultkit-0.2.0}/vaultkit.egg-info/SOURCES.txt +6 -0
  11. vaultkit-0.2.0/vaultkit.egg-info/entry_points.txt +2 -0
  12. vaultkit-0.2.0/vaultkit.egg-info/requires.txt +4 -0
  13. vaultkit-0.1.0/vaultkit.egg-info/requires.txt +0 -1
  14. {vaultkit-0.1.0 → vaultkit-0.2.0}/README.md +0 -0
  15. {vaultkit-0.1.0 → vaultkit-0.2.0}/setup.cfg +0 -0
  16. {vaultkit-0.1.0 → vaultkit-0.2.0}/tests/test_fetch.py +0 -0
  17. {vaultkit-0.1.0 → vaultkit-0.2.0}/tests/test_query.py +0 -0
  18. {vaultkit-0.1.0 → vaultkit-0.2.0}/vaultkit/__init__.py +0 -0
  19. {vaultkit-0.1.0 → vaultkit-0.2.0}/vaultkit/client.py +0 -0
  20. {vaultkit-0.1.0 → vaultkit-0.2.0}/vaultkit/core/__init__.py +0 -0
  21. {vaultkit-0.1.0 → vaultkit-0.2.0}/vaultkit/core/http.py +0 -0
  22. {vaultkit-0.1.0 → vaultkit-0.2.0}/vaultkit/core/polling.py +0 -0
  23. {vaultkit-0.1.0 → vaultkit-0.2.0}/vaultkit/errors/__init__.py +0 -0
  24. {vaultkit-0.1.0 → vaultkit-0.2.0}/vaultkit/errors/base.py +0 -0
  25. {vaultkit-0.1.0 → vaultkit-0.2.0}/vaultkit/errors/exceptions.py +0 -0
  26. {vaultkit-0.1.0 → vaultkit-0.2.0}/vaultkit/models/__init__.py +0 -0
  27. {vaultkit-0.1.0 → vaultkit-0.2.0}/vaultkit/models/dataset_info.py +0 -0
  28. {vaultkit-0.1.0 → vaultkit-0.2.0}/vaultkit/models/dataset_schema.py +0 -0
  29. {vaultkit-0.1.0 → vaultkit-0.2.0}/vaultkit/models/fetch_result.py +0 -0
  30. {vaultkit-0.1.0 → vaultkit-0.2.0}/vaultkit/models/query_result.py +0 -0
  31. {vaultkit-0.1.0 → vaultkit-0.2.0}/vaultkit/tools/__init__.py +0 -0
  32. {vaultkit-0.1.0 → vaultkit-0.2.0}/vaultkit/tools/adapters/__init__.py +0 -0
  33. {vaultkit-0.1.0 → vaultkit-0.2.0}/vaultkit/tools/adapters/anthropic.py +0 -0
  34. {vaultkit-0.1.0 → vaultkit-0.2.0}/vaultkit/tools/adapters/openai.py +0 -0
  35. {vaultkit-0.1.0 → vaultkit-0.2.0}/vaultkit/tools/builder.py +0 -0
  36. {vaultkit-0.1.0 → vaultkit-0.2.0}/vaultkit/tools/executor.py +0 -0
  37. {vaultkit-0.1.0 → vaultkit-0.2.0}/vaultkit/tools/schemas.py +0 -0
  38. {vaultkit-0.1.0 → vaultkit-0.2.0}/vaultkit/utils/__init__.py +0 -0
  39. {vaultkit-0.1.0 → vaultkit-0.2.0}/vaultkit/utils/retry.py +0 -0
  40. {vaultkit-0.1.0 → vaultkit-0.2.0}/vaultkit/utils/validation.py +0 -0
  41. {vaultkit-0.1.0 → vaultkit-0.2.0}/vaultkit.egg-info/dependency_links.txt +0 -0
  42. {vaultkit-0.1.0 → vaultkit-0.2.0}/vaultkit.egg-info/top_level.txt +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: vaultkit
3
- Version: 0.1.0
3
+ Version: 0.2.0
4
4
  Summary: VaultKit Python SDK for policy-driven, runtime governed data access
5
5
  Author-email: VaultKit <founders@vaultkit.io>
6
6
  License: MIT
@@ -8,19 +8,21 @@ Project-URL: Homepage, https://github.com/vaultkit-inc/vaultkit-sdk-python
8
8
  Project-URL: Documentation, https://docs.vaultkit.io
9
9
  Project-URL: Source, https://github.com/vaultkit-inc/vaultkit-sdk-python
10
10
  Project-URL: Issues, https://github.com/vaultkit-inc/vaultkit-sdk-python/issues
11
- Keywords: ai,data,sdk,governance,security,agents,runtime
11
+ Keywords: ai,data,sdk,governance,security,agents,runtime,mcp
12
12
  Classifier: Development Status :: 3 - Alpha
13
13
  Classifier: Intended Audience :: Developers
14
14
  Classifier: License :: OSI Approved :: MIT License
15
15
  Classifier: Programming Language :: Python :: 3
16
- Classifier: Programming Language :: Python :: 3.8
17
- Classifier: Programming Language :: Python :: 3.9
18
16
  Classifier: Programming Language :: Python :: 3.10
19
17
  Classifier: Programming Language :: Python :: 3.11
18
+ Classifier: Programming Language :: Python :: 3.12
19
+ Classifier: Programming Language :: Python :: 3.13
20
20
  Classifier: Topic :: Software Development :: Libraries
21
- Requires-Python: >=3.8
21
+ Requires-Python: >=3.10
22
22
  Description-Content-Type: text/markdown
23
23
  Requires-Dist: httpx>=0.24.0
24
+ Provides-Extra: mcp
25
+ Requires-Dist: mcp<2,>=1.27; extra == "mcp"
24
26
 
25
27
  # VaultKit Python SDK
26
28
 
@@ -4,13 +4,13 @@ build-backend = "setuptools.build_meta"
4
4
 
5
5
  [project]
6
6
  name = "vaultkit"
7
- version = "0.1.0"
7
+ version = "0.2.0"
8
8
  description = "VaultKit Python SDK for policy-driven, runtime governed data access"
9
9
  authors = [
10
10
  { name = "VaultKit", email = "founders@vaultkit.io" }
11
11
  ]
12
12
  readme = "README.md"
13
- requires-python = ">=3.8"
13
+ requires-python = ">=3.10"
14
14
  license = { text = "MIT" }
15
15
 
16
16
  dependencies = [
@@ -25,6 +25,7 @@ keywords = [
25
25
  "security",
26
26
  "agents",
27
27
  "runtime",
28
+ "mcp",
28
29
  ]
29
30
 
30
31
  classifiers = [
@@ -32,13 +33,19 @@ classifiers = [
32
33
  "Intended Audience :: Developers",
33
34
  "License :: OSI Approved :: MIT License",
34
35
  "Programming Language :: Python :: 3",
35
- "Programming Language :: Python :: 3.8",
36
- "Programming Language :: Python :: 3.9",
37
36
  "Programming Language :: Python :: 3.10",
38
37
  "Programming Language :: Python :: 3.11",
38
+ "Programming Language :: Python :: 3.12",
39
+ "Programming Language :: Python :: 3.13",
39
40
  "Topic :: Software Development :: Libraries",
40
41
  ]
41
42
 
43
+ [project.optional-dependencies]
44
+ mcp = ["mcp>=1.27,<2"]
45
+
46
+ [project.scripts]
47
+ vaultkit-mcp = "vaultkit.mcp.__main__:main"
48
+
42
49
  [project.urls]
43
50
  Homepage = "https://github.com/vaultkit-inc/vaultkit-sdk-python"
44
51
  Documentation = "https://docs.vaultkit.io"
@@ -0,0 +1,32 @@
1
+ from __future__ import annotations
2
+
3
+ """
4
+ VaultKit MCP server (the ``[mcp]`` extra).
5
+
6
+ This subpackage exposes VaultKit's governed tools over the Model Context
7
+ Protocol so any MCP host (Claude Desktop, Cursor, custom agents) can query
8
+ governed data.
9
+
10
+ No policy evaluation happens here. This layer advertises tools by reusing
11
+ ``ToolBuilder`` and dispatches calls by reusing ``ToolExecutor``. Every policy
12
+ decision, mask, grant and audit entry is performed by the control plane.
13
+
14
+ Two deployments share one codebase:
15
+ - stdio : one principal from environment variables (local use).
16
+ - http : one principal per authenticated session (not yet implemented;
17
+ see identity.HttpClientResolver).
18
+
19
+ The only difference between them is how the caller's identity is resolved into
20
+ a VaultKitClient; everything else is shared.
21
+
22
+ Install:
23
+ pip install vaultkit[mcp]
24
+
25
+ Run:
26
+ vaultkit-mcp # stdio (default)
27
+ vaultkit-mcp --transport http --host 0.0.0.0 --port 8000 # not yet implemented
28
+ """
29
+
30
+ from .server import McpServerConfig, build_server
31
+
32
+ __all__ = ["McpServerConfig", "build_server"]
@@ -0,0 +1,116 @@
1
+ from __future__ import annotations
2
+
3
+ """
4
+ ``vaultkit-mcp`` entrypoint.
5
+
6
+ vaultkit-mcp # stdio (default), local use
7
+ vaultkit-mcp --transport http --port 8000 # hosted (not yet implemented)
8
+
9
+ stdio is the local transport: an MCP host (Claude Desktop, Cursor, ...) launches
10
+ this as a subprocess and pipes JSON-RPC over stdin/stdout. Credentials come from
11
+ the environment (see StdioClientResolver).
12
+
13
+ http (streamable HTTP) is the hosted transport. It is not wired up yet: it
14
+ requires the per-principal OAuth exchange in HttpClientResolver first.
15
+ """
16
+
17
+ import argparse
18
+ import os
19
+ import sys
20
+ from typing import Optional
21
+
22
+ from .identity import HttpClientResolver, StdioClientResolver
23
+ from .server import McpServerConfig, build_server
24
+
25
+
26
+ def _config_from_env() -> McpServerConfig:
27
+ def _flag(name: str, default: bool) -> bool:
28
+ raw = os.environ.get(name)
29
+ if raw is None:
30
+ return default
31
+ return raw.strip().lower() in ("1", "true", "yes", "on")
32
+
33
+ return McpServerConfig(
34
+ environment=os.environ.get("VAULTKIT_ENVIRONMENT", "production"),
35
+ include_discover=_flag("VAULTKIT_MCP_INCLUDE_DISCOVER", True),
36
+ include_query=_flag("VAULTKIT_MCP_INCLUDE_QUERY", True),
37
+ include_check_approval=_flag("VAULTKIT_MCP_INCLUDE_CHECK_APPROVAL", True),
38
+ fetch_schema_hints=_flag("VAULTKIT_MCP_SCHEMA_HINTS", True),
39
+ default_purpose=os.environ.get("VAULTKIT_MCP_DEFAULT_PURPOSE"),
40
+ default_requester_region=os.environ.get("VAULTKIT_MCP_DEFAULT_REGION"),
41
+ )
42
+
43
+
44
+ async def _run_stdio(server) -> None:
45
+ from mcp.server.stdio import stdio_server
46
+
47
+ async with stdio_server() as (read_stream, write_stream):
48
+ await server.run(
49
+ read_stream,
50
+ write_stream,
51
+ server.create_initialization_options(),
52
+ )
53
+
54
+
55
+ def _run_http(server, host: str, port: int) -> None:
56
+ # Not implemented. Streamable HTTP requires a session manager and an ASGI
57
+ # app, and — before that — the per-principal OAuth exchange in
58
+ # HttpClientResolver. Reference for the intended wiring:
59
+ #
60
+ # from mcp.server.streamable_http_manager import StreamableHTTPSessionManager
61
+ # import uvicorn
62
+ # from starlette.applications import Starlette
63
+ # ... mount the session manager, add OAuth token validation middleware,
64
+ # then uvicorn.run(app, host=host, port=port)
65
+ raise NotImplementedError(
66
+ "Hosted HTTP transport is not implemented yet. Implement "
67
+ "HttpClientResolver (per-principal identity) first, then wire the "
68
+ "streamable-HTTP ASGI app here. Use --transport stdio for now."
69
+ )
70
+
71
+
72
+ def main(argv: Optional[list] = None) -> int:
73
+ parser = argparse.ArgumentParser(
74
+ prog="vaultkit-mcp",
75
+ description="Expose VaultKit's governed tools over the Model Context Protocol.",
76
+ )
77
+ parser.add_argument(
78
+ "--transport",
79
+ choices=("stdio", "http"),
80
+ default=os.environ.get("VAULTKIT_MCP_TRANSPORT", "stdio"),
81
+ help="Transport to serve on (default: stdio).",
82
+ )
83
+ parser.add_argument("--host", default=os.environ.get("VAULTKIT_MCP_HOST", "127.0.0.1"))
84
+ parser.add_argument("--port", type=int, default=int(os.environ.get("VAULTKIT_MCP_PORT", "8000")))
85
+ args = parser.parse_args(argv)
86
+
87
+ try:
88
+ import anyio
89
+ except ImportError:
90
+ print(
91
+ "The MCP extra is not installed. Install it with:\n"
92
+ " pip install vaultkit[mcp]",
93
+ file=sys.stderr,
94
+ )
95
+ return 1
96
+
97
+ config = _config_from_env()
98
+
99
+ if args.transport == "stdio":
100
+ resolver = StdioClientResolver()
101
+ server = build_server(resolver, config)
102
+ try:
103
+ anyio.run(_run_stdio, server)
104
+ finally:
105
+ resolver.close()
106
+ return 0
107
+
108
+ # http
109
+ resolver = HttpClientResolver()
110
+ server = build_server(resolver, config)
111
+ _run_http(server, args.host, args.port)
112
+ return 0
113
+
114
+
115
+ if __name__ == "__main__":
116
+ raise SystemExit(main())
@@ -0,0 +1,118 @@
1
+ from __future__ import annotations
2
+
3
+ """
4
+ Identity resolution for the MCP server.
5
+
6
+ A single interface, ``ClientResolver``, turns an incoming request into a
7
+ ``VaultKitClient``. This is the only part of the MCP layer that differs between
8
+ deployments, which lets ``server.py`` be written once and run in either mode:
9
+
10
+ stdio -> StdioClientResolver : one principal, read from env at startup.
11
+ http -> HttpClientResolver : one principal per authenticated request.
12
+
13
+ The request handlers depend only on the ``ClientResolver`` interface and never
14
+ know which implementation they received.
15
+ """
16
+
17
+ import os
18
+ from typing import Any, Optional
19
+
20
+ from vaultkit.client import VaultKitClient
21
+
22
+
23
+ class ClientResolver:
24
+ """Resolve an incoming request context into a VaultKitClient.
25
+
26
+ ``ctx`` is whatever the transport provides: ``None`` for stdio, or an
27
+ authenticated request context for http. Implementations use as much of it
28
+ as they need.
29
+ """
30
+
31
+ def resolve(self, ctx: Optional[Any] = None) -> VaultKitClient: # pragma: no cover
32
+ raise NotImplementedError
33
+
34
+ def close(self) -> None: # pragma: no cover
35
+ pass
36
+
37
+
38
+ class StdioClientResolver(ClientResolver):
39
+ """Single-principal resolver for local (stdio) use.
40
+
41
+ Reads credentials from the environment once and returns the same client for
42
+ every call. Over stdio there is a single caller (the host process that
43
+ launched the server), so there is a single principal, and ``ctx`` is
44
+ ignored.
45
+
46
+ Required environment variables:
47
+ VAULTKIT_BASE_URL
48
+ VAULTKIT_TOKEN
49
+ VAULTKIT_ORG
50
+ """
51
+
52
+ def __init__(
53
+ self,
54
+ *,
55
+ base_url: Optional[str] = None,
56
+ token: Optional[str] = None,
57
+ org: Optional[str] = None,
58
+ ) -> None:
59
+ self._base_url = base_url or os.environ.get("VAULTKIT_BASE_URL")
60
+ self._token = token or os.environ.get("VAULTKIT_TOKEN")
61
+ self._org = org or os.environ.get("VAULTKIT_ORG")
62
+
63
+ missing = [
64
+ name
65
+ for name, val in (
66
+ ("VAULTKIT_BASE_URL", self._base_url),
67
+ ("VAULTKIT_TOKEN", self._token),
68
+ ("VAULTKIT_ORG", self._org),
69
+ )
70
+ if not val
71
+ ]
72
+ if missing:
73
+ raise RuntimeError(
74
+ "Missing required VaultKit credentials for the MCP server: "
75
+ + ", ".join(missing)
76
+ + ". Set them in the environment (or your MCP host's server "
77
+ "config 'env' block) before starting vaultkit-mcp."
78
+ )
79
+
80
+ self._client: Optional[VaultKitClient] = None
81
+
82
+ def resolve(self, ctx: Optional[Any] = None) -> VaultKitClient:
83
+ if self._client is None:
84
+ self._client = VaultKitClient(
85
+ base_url=self._base_url, # type: ignore[arg-type]
86
+ token=self._token, # type: ignore[arg-type]
87
+ org=self._org, # type: ignore[arg-type]
88
+ )
89
+ return self._client
90
+
91
+ def close(self) -> None:
92
+ if self._client is not None:
93
+ self._client.close()
94
+ self._client = None
95
+
96
+
97
+ class HttpClientResolver(ClientResolver):
98
+ """Per-principal resolver for hosted (streamable-HTTP) use.
99
+
100
+ Not yet implemented. Over http each request may belong to a different
101
+ principal, so a client cannot be built once at startup; it must be resolved
102
+ per request from the authenticated identity.
103
+
104
+ Intended implementation:
105
+ 1. Read the bearer token from ``ctx`` (the request's auth context).
106
+ 2. Resolve it to a (token, org) principal, delegating to the control
107
+ plane rather than trusting client-supplied claims.
108
+ 3. Construct and return a VaultKitClient for that principal.
109
+ 4. Optionally cache clients per principal and close idle ones.
110
+ """
111
+
112
+ def resolve(self, ctx: Optional[Any] = None) -> VaultKitClient:
113
+ raise NotImplementedError(
114
+ "Hosted HTTP identity resolution is not implemented yet. "
115
+ "Run the server with --transport stdio, or implement "
116
+ "HttpClientResolver.resolve to exchange the request's OAuth token "
117
+ "for a VaultKit principal via the control plane."
118
+ )
@@ -0,0 +1,130 @@
1
+ from __future__ import annotations
2
+
3
+ """
4
+ The VaultKit MCP server.
5
+
6
+ Two handlers, both thin:
7
+
8
+ list_tools -> reuse ToolBuilder to advertise the caller's authorized tools.
9
+ call_tool -> reuse ToolExecutor to run a call and return its result.
10
+
11
+ This uses the low-level ``mcp.server.lowlevel.Server`` rather than the
12
+ ``@mcp.tool`` decorator API because the decorator registers a static tool list
13
+ at startup, whereas VaultKit's tool list is per-principal: different callers are
14
+ authorized for different datasets. ``list_tools`` therefore has to be computed
15
+ per session, which the low-level API allows.
16
+
17
+ The VaultKit SDK is synchronous (blocking HTTP and polling), while MCP handlers
18
+ are async. Blocking work is offloaded to a worker thread via
19
+ ``anyio.to_thread.run_sync`` so it does not stall the event loop. This is
20
+ required once multiple callers can be served concurrently, and harmless for the
21
+ single-caller stdio case.
22
+ """
23
+
24
+ import json
25
+ from dataclasses import dataclass
26
+ from typing import List, Optional
27
+
28
+ import anyio
29
+ import mcp.types as types
30
+ from mcp.server.lowlevel import Server
31
+
32
+ from vaultkit.tools.adapters import ToolProvider
33
+ from vaultkit.tools.adapters.mcp import to_mcp_tool
34
+ from vaultkit.tools.builder import ToolBuilder
35
+ from vaultkit.tools.executor import ToolExecutor
36
+
37
+ from .identity import ClientResolver
38
+
39
+
40
+ @dataclass
41
+ class McpServerConfig:
42
+ """Server-wide configuration (not per-call; per-call args come from the agent)."""
43
+
44
+ environment: str = "production"
45
+ include_discover: bool = True
46
+ include_query: bool = True
47
+ # check_approval is exposed by default: the approval flow is asynchronous,
48
+ # so the agent needs a way to poll a pending request to completion.
49
+ include_check_approval: bool = True
50
+ # Schema hints feed the agent the exact valid field names per dataset, which
51
+ # guards against field-name hallucination. Keep on unless a very large
52
+ # catalog makes startup slow.
53
+ fetch_schema_hints: bool = True
54
+ # Optional fallbacks if an agent omits them (agents normally supply purpose).
55
+ default_purpose: Optional[str] = None
56
+ default_requester_region: Optional[str] = None
57
+ server_name: str = "vaultkit"
58
+
59
+
60
+ def build_server(resolver: ClientResolver, config: Optional[McpServerConfig] = None) -> Server:
61
+ """Wire a low-level MCP Server around the given identity resolver.
62
+
63
+ Args:
64
+ resolver: Turns a request context into a VaultKitClient, and thereby
65
+ determines whether this is a single-principal (stdio) or
66
+ per-principal (http) server.
67
+ config: Server-wide options. Defaults are suitable for local (stdio) use.
68
+
69
+ Returns:
70
+ A configured ``mcp.server.lowlevel.Server`` ready to run over any
71
+ transport.
72
+ """
73
+ cfg = config or McpServerConfig()
74
+ server: Server = Server(cfg.server_name)
75
+
76
+ @server.list_tools()
77
+ async def _list_tools() -> List[types.Tool]:
78
+ # Resolve the caller -> client, then build their authorized tool list.
79
+ # RAW gives canonical defs; those are mapped to MCP Tools by to_mcp_tool.
80
+ client = resolver.resolve(_current_ctx(server))
81
+
82
+ def _build():
83
+ builder = ToolBuilder(client)
84
+ return builder.build(
85
+ provider=ToolProvider.RAW,
86
+ environment=cfg.environment,
87
+ include_discover=cfg.include_discover,
88
+ include_query=cfg.include_query,
89
+ include_check_approval=cfg.include_check_approval,
90
+ fetch_schema_hints=cfg.fetch_schema_hints,
91
+ )
92
+
93
+ canonical = await anyio.to_thread.run_sync(_build)
94
+ return [to_mcp_tool(t) for t in canonical]
95
+
96
+ @server.call_tool()
97
+ async def _call_tool(name: str, arguments: dict) -> List[types.ContentBlock]:
98
+ # Resolve the caller -> client, then dispatch through the executor.
99
+ # The executor never raises: denials, pending-approval and masking all
100
+ # come back as a structured dict with a `status` field, which is
101
+ # forwarded verbatim. A policy denial is a valid governed answer, not a
102
+ # protocol error, so it is not raised or marked isError.
103
+ client = resolver.resolve(_current_ctx(server))
104
+
105
+ def _run():
106
+ executor = ToolExecutor(
107
+ client,
108
+ default_purpose=cfg.default_purpose,
109
+ default_requester_region=cfg.default_requester_region,
110
+ )
111
+ return executor.execute(name, arguments or {})
112
+
113
+ result = await anyio.to_thread.run_sync(_run)
114
+ text = json.dumps(result, default=str, ensure_ascii=False, indent=2)
115
+ return [types.TextContent(type="text", text=text)]
116
+
117
+ return server
118
+
119
+
120
+ def _current_ctx(server: Server):
121
+ """Return the active request context, or None if there is none.
122
+
123
+ stdio resolvers ignore this. The http resolver uses it to reach the
124
+ authenticated identity. Accessing ``request_context`` outside a request
125
+ raises, so it is guarded to keep the single-principal case working.
126
+ """
127
+ try:
128
+ return server.request_context
129
+ except Exception:
130
+ return None
@@ -0,0 +1,41 @@
1
+ from __future__ import annotations
2
+
3
+ """
4
+ MCP tool adapter.
5
+
6
+ Converts a canonical VaultKit tool definition into an ``mcp.types.Tool``,
7
+ exactly the way ``to_anthropic_tool`` and ``to_openai_tool`` convert into
8
+ their provider shapes.
9
+
10
+ Canonical shape (from vaultkit.tools.definitions):
11
+ {"name": str, "description": str, "input_schema": {...}}
12
+
13
+ MCP shape (mcp.types.Tool):
14
+ Tool(name=..., description=..., inputSchema={...})
15
+
16
+ The only real work is the ``input_schema`` -> ``inputSchema`` rename and
17
+ wrapping the dict in the MCP type. No governance logic lives here — this is
18
+ pure translation, the same as every other adapter in this package.
19
+ """
20
+
21
+ from typing import Any, Dict
22
+
23
+ import mcp.types as types
24
+
25
+
26
+ def to_mcp_tool(canonical: Dict[str, Any]) -> types.Tool:
27
+ """Convert one canonical tool def into an MCP Tool.
28
+
29
+ Args:
30
+ canonical: A dict with ``name``, ``description`` and ``input_schema``,
31
+ as produced by ``vaultkit.tools.definitions``.
32
+
33
+ Returns:
34
+ An ``mcp.types.Tool`` suitable for returning from a ``list_tools``
35
+ handler.
36
+ """
37
+ return types.Tool(
38
+ name=canonical["name"],
39
+ description=canonical.get("description"),
40
+ inputSchema=canonical["input_schema"],
41
+ )
@@ -63,13 +63,16 @@ def query_tool_def(
63
63
  }
64
64
 
65
65
  # Field guidance
66
- fields_desc = "Columns to retrieve. Omit to return all accessible columns."
66
+ fields_desc = (
67
+ "Columns to retrieve. MUST be valid fields for the selected dataset. "
68
+ "Do NOT invent or guess field names. Only use fields listed below."
69
+ )
67
70
  if schema_hints:
68
- examples = []
69
- for ds, fields in list(schema_hints.items())[:2]:
70
- examples.append(f"{ds}: [{', '.join(fields[:5])}]")
71
- if examples:
72
- fields_desc += f" Example fields — {'; '.join(examples)}."
71
+ field_rules = []
72
+ for ds, fields in list(schema_hints.items())[:5]:
73
+ field_rules.append(f"{ds}: {', '.join(fields)}")
74
+
75
+ fields_desc += "\n\nVALID FIELDS BY DATASET:\n" + "\n".join(field_rules)
73
76
 
74
77
  filter_condition = {
75
78
  "type": "object",
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: vaultkit
3
- Version: 0.1.0
3
+ Version: 0.2.0
4
4
  Summary: VaultKit Python SDK for policy-driven, runtime governed data access
5
5
  Author-email: VaultKit <founders@vaultkit.io>
6
6
  License: MIT
@@ -8,19 +8,21 @@ Project-URL: Homepage, https://github.com/vaultkit-inc/vaultkit-sdk-python
8
8
  Project-URL: Documentation, https://docs.vaultkit.io
9
9
  Project-URL: Source, https://github.com/vaultkit-inc/vaultkit-sdk-python
10
10
  Project-URL: Issues, https://github.com/vaultkit-inc/vaultkit-sdk-python/issues
11
- Keywords: ai,data,sdk,governance,security,agents,runtime
11
+ Keywords: ai,data,sdk,governance,security,agents,runtime,mcp
12
12
  Classifier: Development Status :: 3 - Alpha
13
13
  Classifier: Intended Audience :: Developers
14
14
  Classifier: License :: OSI Approved :: MIT License
15
15
  Classifier: Programming Language :: Python :: 3
16
- Classifier: Programming Language :: Python :: 3.8
17
- Classifier: Programming Language :: Python :: 3.9
18
16
  Classifier: Programming Language :: Python :: 3.10
19
17
  Classifier: Programming Language :: Python :: 3.11
18
+ Classifier: Programming Language :: Python :: 3.12
19
+ Classifier: Programming Language :: Python :: 3.13
20
20
  Classifier: Topic :: Software Development :: Libraries
21
- Requires-Python: >=3.8
21
+ Requires-Python: >=3.10
22
22
  Description-Content-Type: text/markdown
23
23
  Requires-Dist: httpx>=0.24.0
24
+ Provides-Extra: mcp
25
+ Requires-Dist: mcp<2,>=1.27; extra == "mcp"
24
26
 
25
27
  # VaultKit Python SDK
26
28
 
@@ -7,6 +7,7 @@ vaultkit/client.py
7
7
  vaultkit.egg-info/PKG-INFO
8
8
  vaultkit.egg-info/SOURCES.txt
9
9
  vaultkit.egg-info/dependency_links.txt
10
+ vaultkit.egg-info/entry_points.txt
10
11
  vaultkit.egg-info/requires.txt
11
12
  vaultkit.egg-info/top_level.txt
12
13
  vaultkit/core/__init__.py
@@ -15,6 +16,10 @@ vaultkit/core/polling.py
15
16
  vaultkit/errors/__init__.py
16
17
  vaultkit/errors/base.py
17
18
  vaultkit/errors/exceptions.py
19
+ vaultkit/mcp/__init__.py
20
+ vaultkit/mcp/__main__.py
21
+ vaultkit/mcp/identity.py
22
+ vaultkit/mcp/server.py
18
23
  vaultkit/models/__init__.py
19
24
  vaultkit/models/dataset_info.py
20
25
  vaultkit/models/dataset_schema.py
@@ -27,6 +32,7 @@ vaultkit/tools/executor.py
27
32
  vaultkit/tools/schemas.py
28
33
  vaultkit/tools/adapters/__init__.py
29
34
  vaultkit/tools/adapters/anthropic.py
35
+ vaultkit/tools/adapters/mcp.py
30
36
  vaultkit/tools/adapters/openai.py
31
37
  vaultkit/utils/__init__.py
32
38
  vaultkit/utils/retry.py
@@ -0,0 +1,2 @@
1
+ [console_scripts]
2
+ vaultkit-mcp = vaultkit.mcp.__main__:main
@@ -0,0 +1,4 @@
1
+ httpx>=0.24.0
2
+
3
+ [mcp]
4
+ mcp<2,>=1.27
@@ -1 +0,0 @@
1
- httpx>=0.24.0
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes