Skip to content

Split by domain and serve every operation over MCP - #2

Merged
paydii merged 1 commit into
developmentfrom
feature/v1.0.0
Aug 6, 2026
Merged

Split by domain and serve every operation over MCP#2
paydii merged 1 commit into
developmentfrom
feature/v1.0.0

Conversation

@setoelkahfi

Copy link
Copy Markdown
Contributor

The certificate work landed inside the metadata client, where it did not belong, and adding an MCP server was about to make that worse by depending on both halves at once. Six crates now: core carries the transport (JWT auth, the HTTP client, JSON:API envelopes, errors), aso carries App Metadata, signing carries certificates and CSR generation, and frontend holds what the two front ends share so they cannot disagree. aso and signing know nothing about each other, and CI builds each library on its own, because a workspace build compiles them with the server's dependencies already in the graph and proves nothing.

core exists because both domains need Client and ApiKey. Calling that shared transport "aso" would have meant signing depending on App Store Optimization for its HTTP client, a misnomer that only gets worse when provisioning profiles and devices land.

This breaks anyone embedding the library. Rust allows inherent impls only in the crate that defines a type, so every resource that used to be a method on Client is an extension trait now: AppsApi, CertificatesApi, and the rest, with a prelude per domain crate. The methods do not exist until the trait is in scope.

The MCP server exposes 28 tools, every command line operation except certificate revocation, following the xcrs contract in smbcloud-cli: tool names come from the embedder through a macro, so a host can re-expose the same tools under its own namespace without forking the bodies. Contract tests assert the exact tool set, titles under 40 characters, all six description sections, annotation consistency, and a description on every input schema property.

Revocation is not a tool, and a test fails the build if it becomes one. Revoking a signing certificate invalidates every provisioning profile embedding it, for every teammate and every CI job, at once and irreversibly, and no confirmation string a model types on a human's behalf makes that safe. Scoped deletes are exposed and annotated destructive, because a version, a localization, or a screenshot can each be recreated by re-running the tool that made it.

Tool results carry no key material. certificate_create returns the path it wrote the private key to, never the key, since results are read by a model and end up in transcripts. Credentials resolve per call rather than at startup, so an unconfigured server still answers tools/list and then fails naming what is missing; one that refuses to start can tell nobody what it needs.

The MCP Registry marker lives in the CLI crate's README rather than the library's, because the registry fetches the package named in server.json and greps that crate's README for it.

siGit-Code-Cloud-Agent-Session: https://code.sigit.si/cloud/sessions/d8b72f7e-fb25-45ee-a7f7-e2bf826baff3

The certificate work landed inside the metadata client, where it did not
belong, and adding an MCP server was about to make that worse by depending
on both halves at once. Six crates now: core carries the transport (JWT
auth, the HTTP client, JSON:API envelopes, errors), aso carries App
Metadata, signing carries certificates and CSR generation, and frontend
holds what the two front ends share so they cannot disagree. aso and
signing know nothing about each other, and CI builds each library on its
own, because a workspace build compiles them with the server's
dependencies already in the graph and proves nothing.

core exists because both domains need Client and ApiKey. Calling that
shared transport "aso" would have meant signing depending on App Store
Optimization for its HTTP client, a misnomer that only gets worse when
provisioning profiles and devices land.

This breaks anyone embedding the library. Rust allows inherent impls only
in the crate that defines a type, so every resource that used to be a
method on Client is an extension trait now: AppsApi, CertificatesApi, and
the rest, with a prelude per domain crate. The methods do not exist until
the trait is in scope.

The MCP server exposes 28 tools, every command line operation except
certificate revocation, following the xcrs contract in smbcloud-cli: tool
names come from the embedder through a macro, so a host can re-expose the
same tools under its own namespace without forking the bodies. Contract
tests assert the exact tool set, titles under 40 characters, all six
description sections, annotation consistency, and a description on every
input schema property.

Revocation is not a tool, and a test fails the build if it becomes one.
Revoking a signing certificate invalidates every provisioning profile
embedding it, for every teammate and every CI job, at once and
irreversibly, and no confirmation string a model types on a human's behalf
makes that safe. Scoped deletes are exposed and annotated destructive,
because a version, a localization, or a screenshot can each be recreated
by re-running the tool that made it.

Tool results carry no key material. certificate_create returns the path it
wrote the private key to, never the key, since results are read by a model
and end up in transcripts. Credentials resolve per call rather than at
startup, so an unconfigured server still answers tools/list and then fails
naming what is missing; one that refuses to start can tell nobody what it
needs.

The MCP Registry marker lives in the CLI crate's README rather than the
library's, because the registry fetches the package named in server.json
and greps that crate's README for it.

Co-Authored-By: siGit Code <sigit@sigit.si>
siGit-Code-Cloud-Agent-Session: https://code.sigit.si/cloud/sessions/d8b72f7e-fb25-45ee-a7f7-e2bf826baff3
@setoelkahfi setoelkahfi self-assigned this Aug 6, 2026
@setoelkahfi
setoelkahfi requested review from keypair34 and paydii August 6, 2026 06:23
@paydii
paydii merged commit d4b7a5b into development Aug 6, 2026
2 checks passed
@paydii
paydii deleted the feature/v1.0.0 branch August 6, 2026 19:11
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants