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.
Files changed (79) hide show
  1. contexture/__init__.py +94 -0
  2. contexture/__init__.pyi +50 -0
  3. contexture/application.py +106 -0
  4. contexture/cli/__init__.py +59 -0
  5. contexture/cli/__main__.py +12 -0
  6. contexture/cli/main.py +497 -0
  7. contexture/cli/project.py +414 -0
  8. contexture/cli/scaffold.py +140 -0
  9. contexture/cli/templates/project/.gitignore +6 -0
  10. contexture/cli/templates/project/README.md.tmpl +45 -0
  11. contexture/cli/templates/project/assistant/__init__.py.tmpl +8 -0
  12. contexture/cli/templates/project/assistant/role.py.tmpl +29 -0
  13. contexture/cli/templates/project/assistant/skills.py.tmpl +32 -0
  14. contexture/cli/templates/project/assistant/tools.py.tmpl +35 -0
  15. contexture/cli/templates/project/pyproject.toml.tmpl +17 -0
  16. contexture/cli/usage.py +21 -0
  17. contexture/core/README.md +78 -0
  18. contexture/core/__init__.py +87 -0
  19. contexture/core/constants.py +33 -0
  20. contexture/core/emphasis.py +136 -0
  21. contexture/core/errors.py +135 -0
  22. contexture/core/mcp_interface/README.md +63 -0
  23. contexture/core/mcp_interface/__init__.py +53 -0
  24. contexture/core/mcp_interface/prompt.py +105 -0
  25. contexture/core/mcp_interface/resource.py +88 -0
  26. contexture/core/mcp_interface/tool.py +87 -0
  27. contexture/core/model/__init__.py +56 -0
  28. contexture/core/model/binding.py +92 -0
  29. contexture/core/model/channels.py +145 -0
  30. contexture/core/model/disclosure.py +337 -0
  31. contexture/core/model/disclosure_api.py +5 -0
  32. contexture/core/model/execution_api.py +5 -0
  33. contexture/core/model/graph_context.py +45 -0
  34. contexture/core/model/index.py +605 -0
  35. contexture/core/model/manager.py +342 -0
  36. contexture/core/model/node.py +384 -0
  37. contexture/core/model/role.py +382 -0
  38. contexture/core/model/root_selection.py +324 -0
  39. contexture/core/model/runtime.py +70 -0
  40. contexture/core/model/skill.py +90 -0
  41. contexture/core/model/system_api.py +577 -0
  42. contexture/core/model/telemetry.py +157 -0
  43. contexture/core/model/tool.py +156 -0
  44. contexture/core/principal.py +153 -0
  45. contexture/core/types.py +11 -0
  46. contexture/demo/README.md +132 -0
  47. contexture/demo/__init__.py +11 -0
  48. contexture/demo/documents.py +47 -0
  49. contexture/demo/fixtures.py +124 -0
  50. contexture/demo/role.py +86 -0
  51. contexture/demo/server.py +118 -0
  52. contexture/demo/skills.py +82 -0
  53. contexture/demo/tools.py +183 -0
  54. contexture/inspection.py +609 -0
  55. contexture/py.typed +1 -0
  56. contexture/server/__init__.py +105 -0
  57. contexture/server/__init__.pyi +82 -0
  58. contexture/server/application.py +258 -0
  59. contexture/server/binding.py +135 -0
  60. contexture/server/identity.py +233 -0
  61. contexture/server/instructions.py +168 -0
  62. contexture/server/launch.py +96 -0
  63. contexture/server/messages.py +162 -0
  64. contexture/server/options.py +310 -0
  65. contexture/server/root_selector.py +284 -0
  66. contexture/server/server.py +332 -0
  67. contexture/server/surface/__init__.py +292 -0
  68. contexture/server/surface/navigation.py +46 -0
  69. contexture/server/surface/prompts.py +173 -0
  70. contexture/server/surface/resources.py +122 -0
  71. contexture/server/surface/tools.py +118 -0
  72. contexture/web/__init__.py +6 -0
  73. contexture/web/route.py +43 -0
  74. contexture/web/surface.py +268 -0
  75. contexture_mcp-1.0.0.dist-info/METADATA +284 -0
  76. contexture_mcp-1.0.0.dist-info/RECORD +79 -0
  77. contexture_mcp-1.0.0.dist-info/WHEEL +4 -0
  78. contexture_mcp-1.0.0.dist-info/entry_points.txt +3 -0
  79. 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
+ ]
@@ -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())