contexture-mcp 1.0.0__py3-none-any.whl
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.
- contexture/__init__.py +94 -0
- contexture/__init__.pyi +50 -0
- contexture/application.py +106 -0
- contexture/cli/__init__.py +59 -0
- contexture/cli/__main__.py +12 -0
- contexture/cli/main.py +497 -0
- contexture/cli/project.py +414 -0
- contexture/cli/scaffold.py +140 -0
- contexture/cli/templates/project/.gitignore +6 -0
- contexture/cli/templates/project/README.md.tmpl +45 -0
- contexture/cli/templates/project/assistant/__init__.py.tmpl +8 -0
- contexture/cli/templates/project/assistant/role.py.tmpl +29 -0
- contexture/cli/templates/project/assistant/skills.py.tmpl +32 -0
- contexture/cli/templates/project/assistant/tools.py.tmpl +35 -0
- contexture/cli/templates/project/pyproject.toml.tmpl +17 -0
- contexture/cli/usage.py +21 -0
- contexture/core/README.md +78 -0
- contexture/core/__init__.py +87 -0
- contexture/core/constants.py +33 -0
- contexture/core/emphasis.py +136 -0
- contexture/core/errors.py +135 -0
- contexture/core/mcp_interface/README.md +63 -0
- contexture/core/mcp_interface/__init__.py +53 -0
- contexture/core/mcp_interface/prompt.py +105 -0
- contexture/core/mcp_interface/resource.py +88 -0
- contexture/core/mcp_interface/tool.py +87 -0
- contexture/core/model/__init__.py +56 -0
- contexture/core/model/binding.py +92 -0
- contexture/core/model/channels.py +145 -0
- contexture/core/model/disclosure.py +337 -0
- contexture/core/model/disclosure_api.py +5 -0
- contexture/core/model/execution_api.py +5 -0
- contexture/core/model/graph_context.py +45 -0
- contexture/core/model/index.py +605 -0
- contexture/core/model/manager.py +342 -0
- contexture/core/model/node.py +384 -0
- contexture/core/model/role.py +382 -0
- contexture/core/model/root_selection.py +324 -0
- contexture/core/model/runtime.py +70 -0
- contexture/core/model/skill.py +90 -0
- contexture/core/model/system_api.py +577 -0
- contexture/core/model/telemetry.py +157 -0
- contexture/core/model/tool.py +156 -0
- contexture/core/principal.py +153 -0
- contexture/core/types.py +11 -0
- contexture/demo/README.md +132 -0
- contexture/demo/__init__.py +11 -0
- contexture/demo/documents.py +47 -0
- contexture/demo/fixtures.py +124 -0
- contexture/demo/role.py +86 -0
- contexture/demo/server.py +118 -0
- contexture/demo/skills.py +82 -0
- contexture/demo/tools.py +183 -0
- contexture/inspection.py +609 -0
- contexture/py.typed +1 -0
- contexture/server/__init__.py +105 -0
- contexture/server/__init__.pyi +82 -0
- contexture/server/application.py +258 -0
- contexture/server/binding.py +135 -0
- contexture/server/identity.py +233 -0
- contexture/server/instructions.py +168 -0
- contexture/server/launch.py +96 -0
- contexture/server/messages.py +162 -0
- contexture/server/options.py +310 -0
- contexture/server/root_selector.py +284 -0
- contexture/server/server.py +332 -0
- contexture/server/surface/__init__.py +292 -0
- contexture/server/surface/navigation.py +46 -0
- contexture/server/surface/prompts.py +173 -0
- contexture/server/surface/resources.py +122 -0
- contexture/server/surface/tools.py +118 -0
- contexture/web/__init__.py +6 -0
- contexture/web/route.py +43 -0
- contexture/web/surface.py +268 -0
- contexture_mcp-1.0.0.dist-info/METADATA +284 -0
- contexture_mcp-1.0.0.dist-info/RECORD +79 -0
- contexture_mcp-1.0.0.dist-info/WHEEL +4 -0
- contexture_mcp-1.0.0.dist-info/entry_points.txt +3 -0
- contexture_mcp-1.0.0.dist-info/licenses/LICENSE +202 -0
contexture/__init__.py
ADDED
|
@@ -0,0 +1,94 @@
|
|
|
1
|
+
"""Contexture — one Controller framework for agent and human Views.
|
|
2
|
+
|
|
3
|
+
An application declares its roles, skills and tools once against this object
|
|
4
|
+
model. Contexture can publish that declaration through a native MCP server for
|
|
5
|
+
agents and explicit REST routes for human-facing dashboards.
|
|
6
|
+
|
|
7
|
+
It does not run an agent loop, choose tools, or talk to a model. Those belong
|
|
8
|
+
to the runtime that connects.
|
|
9
|
+
|
|
10
|
+
The package is layered, and the layering is the architecture:
|
|
11
|
+
|
|
12
|
+
contexture.core.model the kernel: what a capability is, where it
|
|
13
|
+
hangs, and the five calls an agent makes
|
|
14
|
+
contexture.core.mcp_interface what each MCP primitive carries; still no SDK
|
|
15
|
+
contexture.server compilation and the native MCP Host adapter
|
|
16
|
+
contexture.web the explicit REST/ASGI Host adapter
|
|
17
|
+
|
|
18
|
+
Each layer may import the ones below it and never the reverse. This facade
|
|
19
|
+
exports what a business developer *declares* with, and nothing the framework
|
|
20
|
+
*runs* with: importing it loads neither the forest, nor the five entry points,
|
|
21
|
+
nor `contexture.server`, nor the SDK, so a project that only models context
|
|
22
|
+
pays for only that.
|
|
23
|
+
"""
|
|
24
|
+
|
|
25
|
+
from typing import TYPE_CHECKING
|
|
26
|
+
|
|
27
|
+
if TYPE_CHECKING:
|
|
28
|
+
from .application import Contexture as Contexture
|
|
29
|
+
|
|
30
|
+
from .core import (
|
|
31
|
+
Channels,
|
|
32
|
+
ContextureError,
|
|
33
|
+
DeclarationError,
|
|
34
|
+
DuplicateNameError,
|
|
35
|
+
ModelValidationError,
|
|
36
|
+
NodeNotFoundError,
|
|
37
|
+
Principal,
|
|
38
|
+
PostProcess,
|
|
39
|
+
PreProcess,
|
|
40
|
+
Role,
|
|
41
|
+
Skill,
|
|
42
|
+
Tool,
|
|
43
|
+
binding_instruction,
|
|
44
|
+
current_graph,
|
|
45
|
+
current_principal,
|
|
46
|
+
current_telemetry,
|
|
47
|
+
)
|
|
48
|
+
from .core.constants import PACKAGE_VERSION as __version__
|
|
49
|
+
|
|
50
|
+
# The two planes a declaration writes on arrive through one import, because
|
|
51
|
+
# which of them a thing belongs to is a modelling decision and not a question
|
|
52
|
+
# about this package's directories. `Prompt` and `Resource` are *constructed*
|
|
53
|
+
# where the three above are *subclassed*; that difference is stated in their
|
|
54
|
+
# own docstrings and enforced when a subclass is attempted, not spelled out in
|
|
55
|
+
# an import path a reader has to decode.
|
|
56
|
+
#
|
|
57
|
+
# It costs nothing to put them here: `core.mcp_interface` stands only on the
|
|
58
|
+
# shared ground, so importing this facade still loads no disclosure layer and
|
|
59
|
+
# no SDK.
|
|
60
|
+
from .core.mcp_interface import Prompt, Resource
|
|
61
|
+
|
|
62
|
+
|
|
63
|
+
def __getattr__(name: str) -> object:
|
|
64
|
+
"""Resolve the application facade without pulling it into ``core`` imports."""
|
|
65
|
+
|
|
66
|
+
if name != "Contexture":
|
|
67
|
+
raise AttributeError(f"module {__name__!r} has no attribute {name!r}")
|
|
68
|
+
from .application import Contexture
|
|
69
|
+
|
|
70
|
+
globals()[name] = Contexture
|
|
71
|
+
return Contexture
|
|
72
|
+
|
|
73
|
+
__all__ = [
|
|
74
|
+
"Channels",
|
|
75
|
+
"Contexture",
|
|
76
|
+
"ContextureError",
|
|
77
|
+
"DeclarationError",
|
|
78
|
+
"DuplicateNameError",
|
|
79
|
+
"ModelValidationError",
|
|
80
|
+
"NodeNotFoundError",
|
|
81
|
+
"Principal",
|
|
82
|
+
"Prompt",
|
|
83
|
+
"PostProcess",
|
|
84
|
+
"PreProcess",
|
|
85
|
+
"Resource",
|
|
86
|
+
"Role",
|
|
87
|
+
"Skill",
|
|
88
|
+
"Tool",
|
|
89
|
+
"__version__",
|
|
90
|
+
"binding_instruction",
|
|
91
|
+
"current_graph",
|
|
92
|
+
"current_principal",
|
|
93
|
+
"current_telemetry",
|
|
94
|
+
]
|
contexture/__init__.pyi
ADDED
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
"""Stable authoring API for Contexture applications.
|
|
2
|
+
|
|
3
|
+
Use this namespace for business declarations. ``contexture.server`` is the
|
|
4
|
+
advanced hosting namespace; ``contexture.core`` is implementation detail.
|
|
5
|
+
"""
|
|
6
|
+
|
|
7
|
+
from .application import Contexture as Contexture
|
|
8
|
+
from .core.emphasis import binding_instruction as binding_instruction
|
|
9
|
+
from .core.errors import ContextureError as ContextureError
|
|
10
|
+
from .core.errors import DeclarationError as DeclarationError
|
|
11
|
+
from .core.errors import DuplicateNameError as DuplicateNameError
|
|
12
|
+
from .core.errors import ModelValidationError as ModelValidationError
|
|
13
|
+
from .core.errors import NodeNotFoundError as NodeNotFoundError
|
|
14
|
+
from .core.mcp_interface import Prompt as Prompt
|
|
15
|
+
from .core.mcp_interface import Resource as Resource
|
|
16
|
+
from .core.model.channels import Channels as Channels
|
|
17
|
+
from .core.model.graph_context import current_graph as current_graph
|
|
18
|
+
from .core.model.role import PostProcess as PostProcess
|
|
19
|
+
from .core.model.role import PreProcess as PreProcess
|
|
20
|
+
from .core.model.role import Role as Role
|
|
21
|
+
from .core.model.skill import Skill as Skill
|
|
22
|
+
from .core.model.telemetry import current_telemetry as current_telemetry
|
|
23
|
+
from .core.model.tool import Tool as Tool
|
|
24
|
+
from .core.principal import Principal as Principal
|
|
25
|
+
from .core.principal import current_principal as current_principal
|
|
26
|
+
|
|
27
|
+
__version__: str
|
|
28
|
+
|
|
29
|
+
__all__ = [
|
|
30
|
+
"Channels",
|
|
31
|
+
"Contexture",
|
|
32
|
+
"ContextureError",
|
|
33
|
+
"DeclarationError",
|
|
34
|
+
"DuplicateNameError",
|
|
35
|
+
"ModelValidationError",
|
|
36
|
+
"NodeNotFoundError",
|
|
37
|
+
"Principal",
|
|
38
|
+
"Prompt",
|
|
39
|
+
"PostProcess",
|
|
40
|
+
"PreProcess",
|
|
41
|
+
"Resource",
|
|
42
|
+
"Role",
|
|
43
|
+
"Skill",
|
|
44
|
+
"Tool",
|
|
45
|
+
"__version__",
|
|
46
|
+
"binding_instruction",
|
|
47
|
+
"current_graph",
|
|
48
|
+
"current_principal",
|
|
49
|
+
"current_telemetry",
|
|
50
|
+
]
|
|
@@ -0,0 +1,106 @@
|
|
|
1
|
+
"""The lazy declaration a business project gives to Contexture.
|
|
2
|
+
|
|
3
|
+
``Contexture`` is deliberately only a specification. It records the classes
|
|
4
|
+
that make up one application; it does not construct a Role, open Channels,
|
|
5
|
+
compile an Index, or import the MCP SDK. The server runner consumes this
|
|
6
|
+
object later, once for each build.
|
|
7
|
+
"""
|
|
8
|
+
|
|
9
|
+
from __future__ import annotations
|
|
10
|
+
|
|
11
|
+
from dataclasses import dataclass
|
|
12
|
+
from typing import Sequence, TypeAlias
|
|
13
|
+
|
|
14
|
+
from .core.errors import ModelValidationError
|
|
15
|
+
from .core.mcp_interface import Prompt, Resource
|
|
16
|
+
from .core.model import Channels, Role, Skill, Tool
|
|
17
|
+
|
|
18
|
+
|
|
19
|
+
RootFactory: TypeAlias = type[Role] | type[Skill] | type[Tool]
|
|
20
|
+
|
|
21
|
+
|
|
22
|
+
@dataclass(slots=True, frozen=True, kw_only=True)
|
|
23
|
+
class Contexture:
|
|
24
|
+
"""One application declaration.
|
|
25
|
+
|
|
26
|
+
A project exports exactly one instance:
|
|
27
|
+
|
|
28
|
+
::
|
|
29
|
+
|
|
30
|
+
app = Contexture(name="hello", roots=(Hello,))
|
|
31
|
+
|
|
32
|
+
A command tree that only a person should enter is declared separately but
|
|
33
|
+
compiled into the same canonical Index::
|
|
34
|
+
|
|
35
|
+
app = Contexture(
|
|
36
|
+
name="hello",
|
|
37
|
+
roots=(Hello,),
|
|
38
|
+
prompt_roots=(Commands,),
|
|
39
|
+
prompts=(RunCommand,),
|
|
40
|
+
)
|
|
41
|
+
|
|
42
|
+
The values are classes, never constructed nodes. Importing this module or
|
|
43
|
+
creating ``app`` is therefore safe in a CLI, a test collector, and an IDE.
|
|
44
|
+
``contexture.server.compile_application`` is the first operation that
|
|
45
|
+
builds the declared forest.
|
|
46
|
+
"""
|
|
47
|
+
|
|
48
|
+
name: str
|
|
49
|
+
roots: Sequence[RootFactory]
|
|
50
|
+
#: Complete root trees owned by MCP's user-controlled Prompt plane. They
|
|
51
|
+
#: remain addressable by Prompt and ``goto``, but are absent from
|
|
52
|
+
#: ``contexture_discover``, server routing instructions, and model opens.
|
|
53
|
+
prompt_roots: Sequence[RootFactory] = ()
|
|
54
|
+
channels: type[Channels] | None = None
|
|
55
|
+
prompts: Sequence[type[Prompt]] = ()
|
|
56
|
+
resources: Sequence[type[Resource]] = ()
|
|
57
|
+
|
|
58
|
+
def __post_init__(self) -> None:
|
|
59
|
+
if not isinstance(self.name, str) or not self.name.strip():
|
|
60
|
+
raise ModelValidationError("A Contexture application needs a non-empty `name`.")
|
|
61
|
+
|
|
62
|
+
roots = tuple(self.roots)
|
|
63
|
+
if not roots:
|
|
64
|
+
raise ModelValidationError(
|
|
65
|
+
"A Contexture application needs at least one root Role, Skill, or Tool."
|
|
66
|
+
)
|
|
67
|
+
for root in roots:
|
|
68
|
+
self._require_factory(root, (Role, Skill, Tool), "roots")
|
|
69
|
+
|
|
70
|
+
prompt_roots = tuple(self.prompt_roots)
|
|
71
|
+
for root in prompt_roots:
|
|
72
|
+
self._require_factory(root, (Role, Skill, Tool), "prompt_roots")
|
|
73
|
+
|
|
74
|
+
if self.channels is not None:
|
|
75
|
+
self._require_factory(self.channels, (Channels,), "channels")
|
|
76
|
+
|
|
77
|
+
prompts = tuple(self.prompts)
|
|
78
|
+
for prompt in prompts:
|
|
79
|
+
self._require_factory(prompt, (Prompt,), "prompts")
|
|
80
|
+
|
|
81
|
+
resources = tuple(self.resources)
|
|
82
|
+
for resource in resources:
|
|
83
|
+
self._require_factory(resource, (Resource,), "resources")
|
|
84
|
+
|
|
85
|
+
object.__setattr__(self, "name", self.name.strip())
|
|
86
|
+
object.__setattr__(self, "roots", roots)
|
|
87
|
+
object.__setattr__(self, "prompt_roots", prompt_roots)
|
|
88
|
+
object.__setattr__(self, "prompts", prompts)
|
|
89
|
+
object.__setattr__(self, "resources", resources)
|
|
90
|
+
|
|
91
|
+
@staticmethod
|
|
92
|
+
def _require_factory(
|
|
93
|
+
value: object,
|
|
94
|
+
kinds: tuple[type[object], ...],
|
|
95
|
+
field: str,
|
|
96
|
+
) -> None:
|
|
97
|
+
if isinstance(value, type) and issubclass(value, kinds):
|
|
98
|
+
return
|
|
99
|
+
expected = " or ".join(kind.__name__ for kind in kinds)
|
|
100
|
+
raise ModelValidationError(
|
|
101
|
+
f"`{field}` contains {value!r}; name a {expected} class, not an "
|
|
102
|
+
"already-built object. A declaration stays lazy until it is compiled."
|
|
103
|
+
)
|
|
104
|
+
|
|
105
|
+
|
|
106
|
+
__all__ = ["Contexture", "RootFactory"]
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
"""The `contexture` command: scaffold a project, then serve it.
|
|
2
|
+
|
|
3
|
+
A business project written against this framework contains declarations and
|
|
4
|
+
nothing else. It has no entry point, no `main()`, and no console script of its
|
|
5
|
+
own, because the framework ships the runner:
|
|
6
|
+
|
|
7
|
+
contexture new my-context # write the project
|
|
8
|
+
contexture list # what would be served
|
|
9
|
+
contexture serve # serve it over MCP
|
|
10
|
+
|
|
11
|
+
Three modules, because three clocks. `scaffold` moves when the project
|
|
12
|
+
template does, `project` when the packaging ecosystem does, and `main` when the
|
|
13
|
+
commands do — the same reason `server` is six modules rather than one file.
|
|
14
|
+
`usage` is the shared ground beneath them.
|
|
15
|
+
|
|
16
|
+
This facade is what a test or an embedder names. It is eager rather than lazy:
|
|
17
|
+
unlike `contexture` and `contexture.core`, nothing here is expensive and there
|
|
18
|
+
is no SDK behind any of it — `main` defers that import to the two commands
|
|
19
|
+
that need one, so `new` and `list` still run in an environment without it.
|
|
20
|
+
"""
|
|
21
|
+
|
|
22
|
+
from __future__ import annotations
|
|
23
|
+
|
|
24
|
+
from .main import build_parser, main
|
|
25
|
+
from .project import (
|
|
26
|
+
CONFIG_TABLE,
|
|
27
|
+
DEMO_APP,
|
|
28
|
+
DEMO_PUBLISH,
|
|
29
|
+
DEMO_TARGET,
|
|
30
|
+
ProjectConfig,
|
|
31
|
+
find_project,
|
|
32
|
+
load_application,
|
|
33
|
+
load_roots,
|
|
34
|
+
load_published,
|
|
35
|
+
resolve_target,
|
|
36
|
+
)
|
|
37
|
+
from .scaffold import TEMPLATES, Names, available_templates, new_project, render_file
|
|
38
|
+
from .usage import UsageError
|
|
39
|
+
|
|
40
|
+
__all__ = [
|
|
41
|
+
"CONFIG_TABLE",
|
|
42
|
+
"DEMO_PUBLISH",
|
|
43
|
+
"DEMO_APP",
|
|
44
|
+
"DEMO_TARGET",
|
|
45
|
+
"Names",
|
|
46
|
+
"ProjectConfig",
|
|
47
|
+
"TEMPLATES",
|
|
48
|
+
"UsageError",
|
|
49
|
+
"available_templates",
|
|
50
|
+
"build_parser",
|
|
51
|
+
"find_project",
|
|
52
|
+
"load_application",
|
|
53
|
+
"load_roots",
|
|
54
|
+
"load_published",
|
|
55
|
+
"main",
|
|
56
|
+
"new_project",
|
|
57
|
+
"render_file",
|
|
58
|
+
"resolve_target",
|
|
59
|
+
]
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
"""`python -m contexture.cli`, which the tests use and a developer may.
|
|
2
|
+
|
|
3
|
+
A package needs this where a module got it for free from
|
|
4
|
+
`if __name__ == "__main__"`. The console script named in `pyproject.toml`
|
|
5
|
+
reaches `main` directly and never comes through here.
|
|
6
|
+
"""
|
|
7
|
+
|
|
8
|
+
from __future__ import annotations
|
|
9
|
+
|
|
10
|
+
from .main import main
|
|
11
|
+
|
|
12
|
+
raise SystemExit(main())
|