mcp-server-pixeltable-developer 0.2.1__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.
@@ -0,0 +1,192 @@
1
+ """Typed MCP inputs and outputs."""
2
+
3
+ from __future__ import annotations
4
+
5
+ from typing import Any, Literal
6
+
7
+ from pydantic import BaseModel, ConfigDict, Field, JsonValue
8
+
9
+
10
+ class StrictModel(BaseModel):
11
+ """Base model for stable public result contracts."""
12
+
13
+ model_config = ConfigDict(extra="forbid")
14
+
15
+
16
+ class CatalogEntry(BaseModel):
17
+ """One object in the Pixeltable catalog tree."""
18
+
19
+ model_config = ConfigDict(extra="allow")
20
+
21
+ name: str | None = None
22
+ path: str
23
+ kind: str | None = None
24
+ rows: int | None = None
25
+ columns: int | None = None
26
+ version: int | None = None
27
+ error_count: int | None = None
28
+ base: str | None = None
29
+ entries: list[CatalogEntry] = Field(default_factory=list)
30
+
31
+
32
+ class CatalogResult(StrictModel):
33
+ """Catalog entries below a requested path."""
34
+
35
+ path: str
36
+ entries: list[CatalogEntry]
37
+ tree: CatalogEntry | None = None
38
+
39
+
40
+ class ColumnDescription(BaseModel):
41
+ """Relevant metadata for a table column."""
42
+
43
+ model_config = ConfigDict(extra="allow")
44
+
45
+ name: str
46
+ type_: str
47
+ is_stored: bool | None = None
48
+ is_primary_key: bool | None = None
49
+ is_computed: bool | None = None
50
+ computed_with: str | None = None
51
+ depends_on: list[list[str]] | None = None
52
+ comment: str | None = None
53
+
54
+
55
+ class TableDescription(BaseModel):
56
+ """Schema and metadata reported by ``pxt describe``."""
57
+
58
+ model_config = ConfigDict(extra="allow")
59
+
60
+ id: str
61
+ name: str
62
+ path: str
63
+ kind: str
64
+ columns: dict[str, ColumnDescription]
65
+ indexes: dict[str, Any] = Field(default_factory=dict)
66
+ has_default_idxs: bool = False
67
+ is_view: bool = False
68
+ is_snapshot: bool = False
69
+ version: int
70
+ primary_key: list[str] | str | None = None
71
+
72
+
73
+ class RowsResult(StrictModel):
74
+ """A bounded table preview."""
75
+
76
+ path: str
77
+ rows: list[dict[str, JsonValue]]
78
+ count: int
79
+
80
+
81
+ class RowResult(StrictModel):
82
+ """One row selected by primary key."""
83
+
84
+ path: str
85
+ row: dict[str, JsonValue]
86
+
87
+
88
+ class ErrorsResult(StrictModel):
89
+ """Failed computed-column values for a table."""
90
+
91
+ path: str
92
+ column: str | None = None
93
+ errors: list[dict[str, JsonValue]]
94
+ count: int
95
+
96
+
97
+ class InsertResult(StrictModel):
98
+ """Pixeltable insertion statistics."""
99
+
100
+ path: str
101
+ num_rows: int
102
+ num_computed_values: int
103
+ num_exceptions: int
104
+ columns_with_exceptions: list[str]
105
+ updated_columns: list[str]
106
+
107
+
108
+ class CheckResult(StrictModel):
109
+ """Static validation result for a schema or service file."""
110
+
111
+ kind: Literal["schema", "service"]
112
+ file: str
113
+ valid: bool
114
+ errors: list[str]
115
+ warnings: list[str]
116
+
117
+
118
+ class ReconcileResult(StrictModel):
119
+ """A schema or service reconciliation result."""
120
+
121
+ kind: Literal["schema", "service"]
122
+ operation: Literal["diff", "update", "prune"]
123
+ file: str
124
+ target: str
125
+ pending: bool
126
+ details: JsonValue
127
+
128
+
129
+ class ServiceInfo(BaseModel):
130
+ """Stable service fields with forward-compatible CLI metadata."""
131
+
132
+ model_config = ConfigDict(extra="allow")
133
+
134
+ name: str
135
+ catalog_path: str | None = None
136
+ endpoint: str | None = None
137
+ port: int | None = Field(default=None, ge=1, le=65535)
138
+ state: str | None = None
139
+ error: str | None = None
140
+ app_module: str | None = None
141
+ spec: JsonValue = None
142
+ pid: int | None = None
143
+ process_started_at: float | None = None
144
+
145
+
146
+ class ServiceListResult(StrictModel):
147
+ """Services known to the Pixeltable daemon."""
148
+
149
+ target: str | None = None
150
+ services: list[ServiceInfo]
151
+
152
+
153
+ class ServiceStopResult(StrictModel):
154
+ """Services stopped by a request."""
155
+
156
+ names: list[str]
157
+ details: JsonValue
158
+
159
+
160
+ class ScaffoldResult(StrictModel):
161
+ """A newly generated application or schema file."""
162
+
163
+ project: str
164
+ kind: Literal["service", "schema"]
165
+ file: str
166
+ created: bool
167
+
168
+
169
+ class RecomputeResult(StrictModel):
170
+ """A computed-column recovery plan or execution result."""
171
+
172
+ path: str
173
+ columns: list[str]
174
+ errors_only: bool
175
+ dry_run: bool
176
+ pending: bool
177
+ details: JsonValue
178
+
179
+
180
+ class StatusResource(StrictModel):
181
+ """Redacted server and runtime status."""
182
+
183
+ server_name: str
184
+ server_version: str
185
+ mcp_version: str
186
+ pixeltable_version: str
187
+ project: str
188
+ transport: str
189
+ unsafe_tools_enabled: bool
190
+
191
+
192
+ JsonObject = dict[str, JsonValue]
@@ -0,0 +1,97 @@
1
+ """Focused workflow prompts for Pixeltable application development."""
2
+
3
+ from __future__ import annotations
4
+
5
+ from typing import Annotated, Any
6
+
7
+ from mcp.server.mcpserver import MCPServer
8
+ from pydantic import Field
9
+
10
+
11
+ def register_prompts(server: MCPServer[Any]) -> None:
12
+ """Register the four supported workflow prompts."""
13
+
14
+ @server.prompt(
15
+ name="pixeltable_build_app",
16
+ title="Build a Pixeltable application",
17
+ description="Plan and implement one app.py with TableModel tables and FastAPIRouter routes.",
18
+ )
19
+ def build_app(
20
+ goal: Annotated[str, Field(min_length=1, description="What the application should do.")],
21
+ ) -> str:
22
+ return f"""Build a Pixeltable application for this goal:
23
+
24
+ {goal}
25
+
26
+ Read pixeltable://guidance/app first. Work in one source-controlled application file.
27
+ Start from `pxt init` and `pxt service example --out app.py`; declare stored columns
28
+ with annotations, computed columns with assignments, and HTTP routes with
29
+ `FastAPIRouter` imported from `pixeltable.serving`. Validate, diff, and update in
30
+ that order. Use deterministic local fixtures before adding provider calls."""
31
+
32
+ @server.prompt(
33
+ name="pixeltable_build_rag",
34
+ title="Build Pixeltable retrieval",
35
+ description="Design document or multimodal ingestion, chunking, embedding, and retrieval in Pixeltable.",
36
+ )
37
+ def build_rag(
38
+ source_media: Annotated[
39
+ str,
40
+ Field(min_length=1, description="Document, image, video, or audio inputs to ingest."),
41
+ ],
42
+ query_behavior: Annotated[
43
+ str,
44
+ Field(min_length=1, description="How callers should search and use the retrieved context."),
45
+ ],
46
+ ) -> str:
47
+ return f"""Build a Pixeltable retrieval application.
48
+
49
+ Inputs: {source_media}
50
+ Query behavior: {query_behavior}
51
+
52
+ Use a TableModel application and Pixeltable computed columns. Use the appropriate
53
+ document, image, video, or audio iterator; persist chunks in a view; add the
54
+ modality-appropriate embedding index; and call similarity with a named modality
55
+ argument. Keep the catalog as the system of record. Add a FastAPIRouter retrieval
56
+ route, then validate, diff, update, insert deterministic fixtures, and test
57
+ retrieval."""
58
+
59
+ @server.prompt(
60
+ name="pixeltable_build_agent",
61
+ title="Build a Pixeltable tool-calling agent",
62
+ description="Design an agent whose model responses and tool executions are persisted as computed columns.",
63
+ )
64
+ def build_agent(
65
+ objective: Annotated[str, Field(min_length=1, description="The agent's objective.")],
66
+ tools: Annotated[str, Field(min_length=1, description="The tools the model may call.")],
67
+ ) -> str:
68
+ return f"""Build a persistent Pixeltable tool-calling agent.
69
+
70
+ Objective: {objective}
71
+ Tools: {tools}
72
+
73
+ Declare request, model response, tool-call, tool-result, and final-response columns
74
+ in a TableModel application. Construct tool definitions with `pxt.tools()`, pass
75
+ them to the provider function, and execute requested calls with `invoke_tools()`.
76
+ Preserve provider outputs in their native type. Add an HTTP route, use mocked
77
+ provider results for local wiring tests, and do not claim live-provider coverage."""
78
+
79
+ @server.prompt(
80
+ name="pixeltable_debug_computation",
81
+ title="Debug a Pixeltable computation",
82
+ description="Inspect failed computed values and build a bounded recovery procedure.",
83
+ )
84
+ def debug_computation(
85
+ table: Annotated[str, Field(min_length=1, description="Table or view path with failures.")],
86
+ column: Annotated[str, Field(min_length=1, description="Computed column to diagnose.")],
87
+ ) -> str:
88
+ return f"""Diagnose failures in `{table}.{column}`.
89
+
90
+ Describe the table, list errors filtered to `{column}`, and inspect the input
91
+ columns the expression depends on. Fix the source data, configuration, provider
92
+ credentials, or application code that caused the error. Preview
93
+ `pxt recompute {table} {column} --errors-only -n`; apply it with `-f` only after the
94
+ preview is correct. If the fix changes the computed expression, apply it with a
95
+ schema update, then recompute without `--errors-only`: the update keeps existing
96
+ values. If the column's type must change, rename the column, because an in-place
97
+ type change is unsupported."""
@@ -0,0 +1,134 @@
1
+ """Focused MCP resources for runtime context and Pixeltable guidance."""
2
+
3
+ from __future__ import annotations
4
+
5
+ from importlib.metadata import PackageNotFoundError, version
6
+ from typing import Any
7
+
8
+ from mcp.server.mcpserver import MCPServer
9
+
10
+ from . import __version__
11
+ from .models import CatalogEntry, CatalogResult, StatusResource
12
+ from .runtime import CommandRunner, ServerConfig
13
+
14
+ APP_GUIDANCE = """# Pixeltable application workflow
15
+
16
+ 1. Run `pxt init` once in the project root.
17
+ 2. Start with `pxt service example --out app.py` (or `pxt schema example --brief --out schema.py`).
18
+ 3. Declare tables on `TableModel = pxt.model_base()`. Stored columns use annotations; computed columns use assignments.
19
+ 4. Import `FastAPIRouter` from `pixeltable.serving` and declare HTTP routes on it.
20
+ Keep tables, computed columns, and routes in the source-controlled application file.
21
+ 5. Validate with `pxt service check app.py`, inspect with
22
+ `pxt service diff app.py TARGET`, then apply with
23
+ `pxt service update app.py TARGET`.
24
+
25
+ Stored columns are non-nullable by default. Write `pxt.String | None` when null is allowed. Do not use `pxt.Required`.
26
+ Create computed columns declaratively. To change a computed expression, edit it and
27
+ run `pxt schema update`: it records the new expression and keeps the stored values,
28
+ so run `pxt recompute TABLE COLUMN -f` to refresh existing rows. Changing a column's
29
+ type is UNSUPPORTED and applies nothing, even with `--allow-destructive`: rename a
30
+ computed column instead, and declare a stored column `T | None` up front.
31
+ Use Pixeltable iterators, embedding indexes, and `pxt.tools()` / `invoke_tools()`
32
+ for multimodal retrieval and agents. Do not add a separate dataframe store or
33
+ vector database.
34
+ For failures, inspect `pxt errors TABLE` and preview
35
+ `pxt recompute TABLE COLUMN --errors-only -n` before applying it with `-f`.
36
+
37
+ Row-addressed operations (`pxt get`, `pxt errors`) require a primary key.
38
+ `pxt service example` generates one: `id = pxt.Column(value=pxtf.uuid.uuid7(), primary_key=True)`,
39
+ computed on insert. Declare a key in every model before its first schema update:
40
+ Pixeltable cannot add a primary key to a table that already exists.
41
+ """
42
+
43
+
44
+ CLOUD_GUIDANCE = """# Pixeltable Cloud preparation
45
+
46
+ Cloud behavior in this server is source-reviewed but not live-tested. Review each diff before applying it.
47
+
48
+ 1. Sign in with `pxt login`, or export `PIXELTABLE_API_KEY`, which wins over a sign-in.
49
+ 2. Add `[[pixeltable.database]]` with `name = 'pxt://ORG:DATABASE'` to `pixeltable.toml`.
50
+ 3. Set provider keys with `pxt secret set pxt://ORG OPENAI_API_KEY=...`. Never put
51
+ secrets in `pixeltable.toml`: a database entry with a `secrets` mapping fails to load.
52
+ 4. Run `pxt db diff`, then `pxt db update pxt://ORG:DATABASE -f`. The first update creates the database.
53
+ 5. Run `pxt schema diff` and `pxt schema update` against the hosted target.
54
+ 6. Run `pxt service diff` and `pxt service update` only after the database code and schema are current.
55
+
56
+ The MCP schema and service tools accept explicit `pxt://` targets. They never
57
+ create databases or set secrets. A hosted `schema_update` or `service_update` call
58
+ changes that hosted target, so inspect the corresponding diff first.
59
+ """
60
+
61
+
62
+ def _distribution_version(name: str) -> str:
63
+ try:
64
+ return version(name)
65
+ except PackageNotFoundError:
66
+ return "not-installed"
67
+
68
+
69
+ def register_resources(server: MCPServer[Any], config: ServerConfig, runner: CommandRunner) -> None:
70
+ """Register the four supported resources."""
71
+
72
+ @server.resource(
73
+ "pixeltable://status",
74
+ name="pixeltable_status",
75
+ title="Pixeltable MCP status",
76
+ description="Redacted server, package, project, and feature-mode versions.",
77
+ mime_type="application/json",
78
+ )
79
+ def status_resource() -> str:
80
+ status = StatusResource(
81
+ server_name="pixeltable-developer",
82
+ server_version=__version__,
83
+ mcp_version=_distribution_version("mcp"),
84
+ pixeltable_version=_distribution_version("pixeltable"),
85
+ project=config.project_root.name,
86
+ transport=config.transport,
87
+ unsafe_tools_enabled=config.unsafe_enabled,
88
+ )
89
+ return status.model_dump_json()
90
+
91
+ @server.resource(
92
+ "pixeltable://catalog",
93
+ name="pixeltable_catalog",
94
+ title="Pixeltable catalog",
95
+ description="Tables, views, and directories in the configured local catalog.",
96
+ mime_type="application/json",
97
+ )
98
+ async def catalog_resource() -> str:
99
+ result = await runner.pxt(["ls", "--tree", "--json"])
100
+ if not isinstance(result.data, dict):
101
+ raise RuntimeError("Pixeltable returned an unexpected catalog listing")
102
+ tree_payload = result.data.get("tree")
103
+ entries_payload = result.data.get("entries", [])
104
+ if isinstance(tree_payload, dict):
105
+ entries_payload = tree_payload.get("entries", entries_payload)
106
+ if not isinstance(entries_payload, list):
107
+ raise RuntimeError("Pixeltable returned an unexpected catalog listing")
108
+ tree = CatalogEntry.model_validate(tree_payload) if tree_payload is not None else None
109
+ catalog = CatalogResult(
110
+ path="",
111
+ entries=[CatalogEntry.model_validate(entry) for entry in entries_payload],
112
+ tree=tree,
113
+ )
114
+ return catalog.model_dump_json()
115
+
116
+ @server.resource(
117
+ "pixeltable://guidance/app",
118
+ name="pixeltable_application_guidance",
119
+ title="Pixeltable application guidance",
120
+ description="Application-first workflow aligned with Pixeltable 0.7.16 and skill 2.12.0.",
121
+ mime_type="text/markdown",
122
+ )
123
+ def application_guidance_resource() -> str:
124
+ return APP_GUIDANCE
125
+
126
+ @server.resource(
127
+ "pixeltable://guidance/cloud",
128
+ name="pixeltable_cloud_guidance",
129
+ title="Pixeltable Cloud preparation",
130
+ description="Reviewed deployment ordering and configuration guidance; not live-tested.",
131
+ mime_type="text/markdown",
132
+ )
133
+ def cloud_guidance_resource() -> str:
134
+ return CLOUD_GUIDANCE