Skip to content

Plug-in internal integration specifications ​

This article is intended for Mogick product internal integrators and is not a plug-in market release specification.

To learn how to use the plug-in page, see Plugins.

This article uses mogick-v26.7.17 as the only implementation baseline and describes the fields that the host currently actually reads, confirms and projects. The current delivery method is internal product integration: ordinary plug-ins are verified in the directory, and product connectors are placed in the built-in plug-in directory along with the application. Currently, there is no plug-in market release process, plug-in compressed package installation capability, and no self-service permission authorization process for third parties.

Scope of application ​

This specification covers two types of packages:

  • Ordinary plug-in: Provide capabilities such as agent capability, file renderer, file opener, MCP or Skill through ordinary manifest contribution. Successful parsing only means that the manifest is legal; non-built-in plug-ins must also be written by the host with a confirmed permission grant. Only after compatibility, permissions, running status, and mutual exclusion selections can they enter effective projection. Although the parser can read the externalConnectors field, installing the same directory as a normal local plugin will not bring it into 26.7.17's connector auto-detection, nor will it generate a supported detected connector sidecar; current connector delivery is limited to the product built-in trusted paths listed below.
  • Product built-in connector plug-in: declare externalConnectors, put it into the host's built-in plug-in directory with the product, and the built-in connector provider will automatically enumerate, load and detect the native product. Only records with source: builtin and trustLevel: host-bundled belong to this trust domain.

This article does not define public network distribution, market review, signature release, remote download, compressed package installation or third-party self-service authorization. When these capabilities are needed, product implementation and separate security design must be completed first, and this article cannot be regarded as a commitment.

Plug-in package structure ​

The host treats the plug-in package as a directory, and the plugin.json in the root directory is the only required file:

text
com.example.analysis/
├─ plugin.json # Required; must be located in the package root directory
├─ assets/ # Optional; static resources such as icons
├─ runtime/ # Optional; plug-in’s own runtime entry
└─ skills/ # Optional; Skills provided with the package

package.json, installation scripts, build scripts and specific compression formats are not part of the plugin contract. The local installation entry of 26.7.17 only accepts directories; when packageKind is not directory, it directly returns plugin.archive-not-supported. The physical location of the product's built-in connector is plugins/builtin/<plugin-id>/ packaged by the host. The packaging state should ensure that files that need to be read by external processes fall into the accessible unpacked entity directory.

The mechanism of plug-in from declaration to taking effect ​

A contribution will pass through three levels of states in sequence, and they cannot be confused:

  1. manifest declaration state: The host reads plugin.json in the package root directory and executes mogick.plugin.v1 parsing. Field shapes, enumerations, ID conflicts and disabled script keys are confirmed here, but payloads such as MCP in provides will be strictly parsed during subsequent consumption.
  2. Host confirmed state: After installation or built-in directory merging, the host records the source, trust level, start and stop status, health status, installation sidecar and grantedPermissions. The initial grantedPermissions of ordinary local plug-ins is empty; product integration must be written and audited by the controlled process on the host side to confirm the grant. List self-reported permissions are not equivalent to authorization.
  3. Final effective projection: The host checks compatibility, confirmed permissions, runtime availability, exclusive group selection and MCP payload, then writes the selected contribution to effectiveContributions and projects it to mcp-config, skill-resolver, file processing registry or tool registry. Claims that are not selected or fail validation will not become current capabilities.

Built-in trusted plug-ins are a clear exception: only source === "builtin" and trustLevel === "host-bundled" are met to skip the compatibility and permission admission of ordinary plug-ins. The connector provider enumerates packages with non-empty externalConnectors from the built-in directory, currently only using the first item of the array for product detection; therefore a product connector package should declare only one main connector contribution.

plugin.json Top-level fields ​

Top-level field table ​

FieldRequiredType or allowed valuesCurrent behavior
schemaVersionYesFixed to mogick.plugin.v1Other values are rejected with manifest.unsupportedSchema.
idYesA non-empty string; internal specifications require stable reverse domain name IDs, such as com.example.analysisThe parser only checks for non-empty, and does not check the naming format for the team; local installations will also reject IDs reserved by the host's built-in directory.
versionYesNon-empty stringparser currently does not do SemVer verification; integrators should still use a comparable stable version.
displayNameisa non-empty stringas the default display name.
publisherisan objectParses the publisher fields as per the table.
hostCompatibilityisan objectA nullable object; non-built-in contributions use its contents on subsequent admissions.
contributionsis anobjectcontaining at least one non-empty contribution array, otherwise rejected with manifest.invalidField.
descriptionNoStringLeave as is; non-empty is not currently required.
localesNoObject mapping of locale to { displayName?, description? }Internal delivery specification requires that the locale key and at least one copy field be non-null after trim. 26.7.17 The parser will trim the locale key, but the text is mainly judged by the true value of the string: "" will fail, and pure blank strings may still pass; empty mappings can currently also pass. Don't rely on these lax behaviors.
iconNoRelative paths to SVG, PNG, JPG, JPEG or WebP in the packageUniform verification after backslash; absolute paths, drive letter paths, empty segments, ., .. or other extensions will be rejected.
licenseNoStringLeave as is, do not verify the license ID.
homepageNoStringLeave as is without URL verification.
repositoryNoStringLeave as is without URL verification.
packageIntegrityNoObjectParsing algorithm and digest declaration; the catalog installer of 26.7.17 does not recompute or validate digests.
runtimeRequired conditionObjectCan be omitted if it does not contain MCP; ordinary contribution must provide a legal top-level runtime as long as it contains any MCP, otherwise access will be denied according to permission-denied. stdio uses kind: subprocess; HTTP's internal specification uses { "kind": "none" }.
permissionsNoPermission declaration arrayOnly accept the kind listed below; this is the application scope, not the confirmed grant.

Unrecognized top-level keys will not enter the manifest returned by the parser; but once scripts, install, postinstall, preinstall or commands appear at any level, the entire manifest will be treated as an installation script or host command declaration and rejected.

publisher ​

FieldRequiredType or allowed valuesCurrent behavior
publisher.idYesNon-empty stringReserved as the publisher's stable ID.
publisher.displayNameYesNon-empty stringReserved as the publisher display name.
publisher.verifiedNobooleanboolean will be retained; other types are currently treated as not provided, rather than reporting an error. Don't rely on this lax behavior.
publisher.contactNoStringNon-string will be rejected; contact format is not currently verified.

hostCompatibility ​

FieldRequiredType or allowed valuesCurrent behavior
hostCompatibility.mogickAppDesktopNoStringparser Holds only strings; currently not a built-in contribution As long as the value is non-null, it is treated as host-incompatible, version range matching has not yet been performed.
hostCompatibility.pluginApiNoStringSame as mogickAppDesktop: non-empty makes the current non-builtin contribution incompatible.
hostCompatibility.platformsNoArray of darwin-arm64, darwin-x64, linux-x64, win32-x64Not provided or an empty array means no limit; non-built-in contributions must contain the current host platform. Unknown values ​​are rejected during parsing.

Therefore, ordinary plug-ins should not fill in non-empty mogickAppDesktop or pluginApi in 26.7.17; the product's built-in trusted connector can carry the product version description because it follows the host-bundled trust path, but the true compatibility should still be verified in the packaging test.

runtime and resourceLimits ​

FieldRequiredType or allowed valuesCurrent behavior
runtime.kindruntime when present isnone, subprocess, renderer-isolate, wasm-workerUnknown value rejected. A normal contribution containing any MCP must have a top-level runtime; stdio must declare subprocess, the internal delivery of HTTP uses none.
runtime.entryNoStringReserved only; the manifest parser does not currently verify that the file exists or is located within the package.
runtime.protocolNojson-rpc, stdio-json-rpc, http-local, custom-hostedUnknown value rejected.
runtime.minHostApiNoStringReserved only; 26.7.17 admission logic does not compare this version yet.
runtime.resourceLimitsNoObjectsNon-objects are currently treated as unprovided; objects are shallow copied as-is, and the parser does not validate values on an item-by-item basis.
resourceLimits.maxMemoryMbNonumberThe type is declared as number, but the current parser does not do runtime verification or enforcement.
resourceLimits.startupTimeoutMsNonumberThe type is declared as number, but the current parser does not do runtime verification or enforcement.
resourceLimits.requestTimeoutMsNonumberThe type is declared as number, but the current parser does not do runtime verification or enforcement.
resourceLimits.maxConcurrentRequestsNonumberThe type is declared as number, but the current parser does not do runtime verification or enforcement.

Don't treat unenforced resourceLimits as a security sandbox. Product review still requires setting host-side limits on process lifecycle, resource consumption, and failure recovery.

packageIntegrity ​

FieldRequiredType or allowed valuesCurrent behavior
packageIntegrity.algorithmpackageIntegrity when present issha256 or sha512Unknown value rejected.
packageIntegrity.digestpackageIntegrity, when present, isa non-empty stringreserved as a package digest declaration.
packageIntegrity.filesNoArray of resource digest objectsEach must have a non-empty path, an algorithm of sha256/sha512, and a non-empty digest; optional sizeBytes must be a number greater than or equal to 0. Empty arrays are currently passed.

Permission and contribution contract ​

Permission Statement ​

FieldRequiredType or allowed valuesCurrent behavior
workspace.readNo{ kind, patterns?: string[] }patterns, if present, must all be non-empty strings; empty arrays are passed.
workspace.writeNo{ kind, patterns?: string[] }Same as workspace.read.
file.renderNo{ kind, maxFileSizeMb?: number }Anything other than number will be rejected; there is currently no check for positive, negative or enforced limits.
networkNo{ kind, hosts: string[] }hosts must be a non-empty string array with at least one item. HTTP MCP will automatically add network to the required permission set.
externalProcess.launchNo{ kind, targets?: string[] }targets, if present, must all be non-empty strings. stdio MCP automatically requires this permission.
externalProduct.discoverNo{ kind, productIds?: string[] }productIds must be a non-empty string if present.
mcp.serverNo{ kind, serverIds: string[] }serverIds must be a non-empty string array of at least one item; any MCP assertion automatically requires this permission.
agent.toolNo{ kind, toolIds?: string[] }toolIds, if present, must all be non-empty strings.

requiredPermissions, top-level permissions and host grantedPermissions are three things: the former describes the requirements for a certain contribution, the second declares the scope of plug-in application, and the third is the authorization confirmed by the host. Ordinary plug-ins will only pass if the required kind appears in both the declaration and the confirmed grant; fine-grained scopes such as target, host or server ID have not yet been cross-checked in the contribution admission of 26.7.17, and the internal authorization process cannot therefore omit manual review.

contribution type ​

FieldRequiredType or allowed valuesCurrent behavior
contributions.agentCapabilitiesNoArray of contribution objectsRegistered as agent-capabilities; MCP, Skills or tools can be declared via provides.
contributions.fileRenderersNoArray of contribution objectsRegistered as file-renderer; projected into the file renderer registry when selected.
contributions.fileOpenersNoArray of contribution objectsRegistered as file-opener; projected into the file opener registry when selected.
contributions.externalConnectorsNoarray of contribution objectsparser will be registered as external-connector; but 26.7.17 only built-in connector provider Enumerates such packages from host plugins/builtin, reads first item and creates builtin / host-bundled detected sidecar. A normal local installation, even if resolvable, does not therefore become a supported connector delivery.
contributions.exclusiveGroupsNoArray of mutually exclusive group declarationsEach requires a non-empty id, a owner of host or third-party, and a selectionPolicy of { userSelectable: boolean }; the group ID must be unique within the array. The hosting policy only honors declarations from the built-in host-bundled plugin.
The id of the first four types of contributions must be unique within the entire plugin, not just within their respective arrays. Each id must be non-empty; hostDefault, if present, must be a boolean; exclusiveGroup, if present, must be a non-empty string. requiredPermissions If present, the internal integration rules require at least one item and each item must be a non-empty kind supported by the above table; 26.7.17 parser will verify the elements, but will not reject empty arrays individually, so empty arrays should be rejected or fields should be omitted directly during review. Other fields specific to the contribution are retained for subsequent consumers.

contributions must have at least one non-empty array. Writing just an empty object, just an empty array, or making all arrays empty will be rejected.

provides.mcpServers of normal manifest contribution ​

This section only describes the common, non-connector manifest contribution consumption path; built-in connectors follow the provider-specific path in the next section, and fields and default values cannot be mixed. The top-level manifest parser will retain the provides of the contribution, and the actual MCP field verification occurs after the contribution has entered the projection candidate. provides.mcpServers must be an array, and the MCP id within the same contribution must be unique.

FieldRequiredType or allowed valuesCurrent behavior
idisa non-empty stringthat forms the runtime global ID <plugin-id>/<server-id>.
nameisa non-empty stringused as the MCP display name and configuration name.
transportYesstdio or httpOther values rejected.
isolationNoshared or per-sessionDefault shared.
useProxyNobooleanDefault true.
commandstdio is anon-empty stringnormalized to the local command path after parsing the template.
argsstdioString arrayEach item expansion template; currently allows empty strings.
envstdiostring to string mappingExpand template for each value.
urlhttp is anon-empty stringused as the HTTP MCP address after expanding the template.
headershttpstring to string mappingExpand template for each value.
activationNo; only built-in trusted plugins{ provider: "product-runtime", productId, capability, mode: "headless-or-attach" }Only source: builtin and trustLevel: host-bundled can be used; third-party or ordinary local plugins will be rejected and fail closed.
Ordinary manifest MCP only allows two template variables, ${pluginRoot} and ${userWorkspace}. Unknown variables will cause the MCP projection of this contribution to fail. As long as the contribution contains any MCP, the admission logic requires the presence of a top-level runtime in the manifest: stdio MCP must use runtime.kind: subprocess and requires externalProcess.launch and mcp.server; the product internal specification for HTTP MCP uses runtime: { "kind": "none" } and requires network and mcp.server. If runtime is missing, or the runtime of stdio MCP is not subprocess, it will be rejected with permission-denied. Permissions must be declared at the top level and confirmed by the host.

provides.mcpServers for built-in connectors ​

Connector MCP does not go through the plugin-manifest-mcp-entries resolver from the previous section. 26.7.17 There are two connector sources: the static provider reads externalConnectors[0].provides.mcpServers; when the helper is configured, connector-runtime-helper reads the mcpServers of the helper JSON. The two are first written into the connector sidecar. Only when the connector is detected, launchFileStatus is confirmed, the plug-in is enabled and the contribution has been projected, the MCP runtime will be entered.

FieldsInternal Product RequirementsStatic provider current behaviorhelper JSON current behavior
idNon-empty after trim, and unique within the same connectorOnly required to be a string; whole items that are not strings are filtered, and no null values or duplicates are checkedSame as static paths; only required to be a string, no null values or duplicates are checked
nameNon-empty after trimOnly required to be a string; otherwise the entire item is filteredSame as static path
transportstdio or httpOnly exact http is retained as HTTP, other values (including missing or unknown values) are normalized to stdioSame as static paths
isolationExplicitly fill in shared or per-sessionOnly precise shared takes shared, other values ​​default to per-sessionOnly precise per-session takes per-session, other values ​​default to shared
commandstdio required and audited non-empty pathstring will expand the connector template and normalize; other types are discardedstring will be normalized; helper must directly output the parsed path and no longer expand the template
argsstdio optional string arrayFilter non-string items, and expand the connector template item by itemFilter non-string items, do not expand the template
envstdio optional string mapFilter non-string values, and expand the connector templateFilter non-string values, do not expand the template
endpointHTTP required and non-empty addressstring will expand the connector template; mapped to the url of MCP config during projectionstring is left as is; mapped to url of MCP config during projection
headersMust not currently be relied upon26.7.17 Connector paths do not read or project this field26.7.17 Helper paths also do not read or project this field
useProxyOptional booleanDefaults to true if not boolean or omittedSame as static path
activationOnly use supported product-runtime shapes if the helper is delivered and approved by the hostStatic provider does not read this fieldLegal objects are retained; illegal objects are silently discarded

The connector provider will construct a new MCP object, and fields outside the table will not be penetrated as they are; many type errors will be filtered, defaulted, or silently discarded, instead of strictly reporting errors like ordinary manifest MCP. Therefore, product internal delivery must additionally verify that the MCP id is non-empty and unique, HTTP must have a non-empty endpoint, stdio must have a non-empty command, and the legal transport and isolation must be explicitly filled in. The url / headers contract used by normal MCP is not portable to connectors: connector HTTP only consumes endpoint, not currently headers.

provides.skills ​

Skill declaration contains at least:

FieldRequiredType or allowed valuesCurrent behavior
idisa non-empty stringas the stable ID of the Skill bundle.
pathYesNon-empty stringOrdinary local plug-ins must be resolved to the plug-in root directory; if the path does not exist, the detailed capabilities will not be entered.

Normal plugin detail projection currently only expands ${pluginRoot}. Skill declarations that end up escaping the plugin root, contain other template variables, or point to non-existing directories are ignored. The connector's Skill path belongs to another built-in provider path, which can be used after product discovery using ${installRoot} qualified below.

Complete example of common plug-in ​

The following package will be parsed via the mogick.plugin.v1 manifest; it declares a stdio MCP and an in-package Skills directory:

json
{
  "schemaVersion": "mogick.plugin.v1",
  "id": "com.example.analysis",
  "version": "1.0.0",
  "displayName": "Example Analysis",
  "publisher": {
    "id": "example",
    "displayName": "Example Team"
  },
  "hostCompatibility": {
    "platforms": ["win32-x64"]
  },
  "runtime": {
    "kind": "subprocess",
    "entry": "runtime/example-mcp.exe",
    "protocol": "stdio-json-rpc"
  },
  "permissions": [
    {
      "kind": "externalProcess.launch",
      "targets": ["example-mcp"]
    },
    {
      "kind": "mcp.server",
      "serverIds": ["analysis"]
    }
  ],
  "contributions": {
    "agentCapabilities": [
      {
        "id": "analysis",
        "displayName": "Example Analysis",
        "requiredPermissions": ["externalProcess.launch", "mcp.server"],
        "exclusiveGroup": "com.example.analysis.engine",
        "provides": {
          "mcpServers": [
            {
              "id": "analysis",
              "name": "example-analysis",
              "transport": "stdio",
              "isolation": "per-session",
              "command": "${pluginRoot}/runtime/example-mcp.exe",
              "args": ["--workspace", "${userWorkspace}"],
              "useProxy": true
            }
          ],
          "skills": [
            {
              "id": "analysis-skills",
              "path": "${pluginRoot}/skills"
            }
          ]
        }
      }
    ]
  }
}

The fact that the packet can be parsed does not mean that the MCP is authorized. The grantedPermissions of ordinary local plug-in installation records is initially empty; during product integration, the host also needs to write the confirmed grant of externalProcess.launch and mcp.server in a controlled manner, and retain the authorization time and audit evidence, and then the contribution can enter the effective projection. 26.7.17 There is no self-service authorization interface or process provided to third parties.

Complete example of built-in product connector ​

The following example provides both a connector helper and a static discovery fallback. The helper's commands, args and connectorRuntime.env only use the reliable ${pluginRoot}; MCP and Skills after successful static discovery use the built-in ${installRoot}, ${installRootBasename}, or you can use ${productVersion} or dynamic variables successfully parsed by context-root:

json
{
  "schemaVersion": "mogick.plugin.v1",
  "id": "com.example.product-connector",
  "version": "1.0.0",
  "displayName": "Example Product Connector",
  "publisher": {
    "id": "example",
    "displayName": "Example Team",
    "verified": true
  },
  "hostCompatibility": {
    "mogickAppDesktop": ">=26.7.17",
    "platforms": ["win32-x64"]
  },
  "runtime": {
    "kind": "none"
  },
  "permissions": [
    {
      "kind": "externalProduct.discover",
      "productIds": ["example-product"]
    },
    {
      "kind": "externalProcess.launch",
      "targets": ["Example Product"]
    },
    {
      "kind": "mcp.server",
      "serverIds": ["example-product"]
    }
  ],
  "contributions": {
    "externalConnectors": [
      {
        "id": "default",
        "displayName": "Example Product",
        "exclusiveGroup": "com.example.product.connector",
        "requiredPermissions": [
          "externalProduct.discover",
          "externalProcess.launch",
          "mcp.server"
        ],
        "product": {
          "productId": "example-product",
          "displayName": "Example Product",
          "envVar": "EXAMPLE_PRODUCT_HOME",
          "exampleFolder": "Example Product 2026"
        },
        "connectorRuntime": {
          "command": "${pluginRoot}/bin/example-connector-helper.exe",
          "args": ["--plugin-root", "${pluginRoot}"],
          "env": {
            "EXAMPLE_CONNECTOR_PLUGIN_ROOT": "${pluginRoot}"
          },
          "timeoutMs": 10000
        },
        "discovery": [
          {
            "kind": "environment-variable",
            "names": ["EXAMPLE_PRODUCT_HOME"]
          },
          {
            "kind": "known-location",
            "platform": "win32-x64",
            "searchParents": ["%ProgramFiles%/Example"],
            "installDirPattern": "Example Product *",
            "requiredFiles": [
              "bin/example-product.exe",
              "bin/example-mcp.exe"
            ]
          }
        ],
        "provides": {
          "mcpServers": [
            {
              "id": "example-product",
              "name": "example-product-mcp",
              "transport": "stdio",
              "isolation": "per-session",
              "command": "${installRoot}/bin/example-mcp.exe",
              "args": [
                "--install-root",
                "${installRoot}",
                "--install-label",
                "${installRootBasename}"
              ],
              "useProxy": true
            }
          ],
          "skills": [
            {
              "id": "example-product-skills",
              "path": "${installRoot}/skills"
            }
          ]
        }
      }
    ]
  }
}

Connector fields and discovery order ​

"Required" in the following table indicates mandatory specifications for product internal delivery, and does not mean that the 26.7.17 provider has strictly reported errors item by item for missing, empty strings or filtered empty arrays. The "Current Behavior" column is dedicated to recording the actual checksum normalization performed by the provider; internal audits must perform the stricter side of the two.

FieldRequiredType or allowed valuesCurrent behavior
product.productIdInternally requiredNon-empty stringInternal delivery must provide a stable non-empty product ID; 26.7.17 provider only validates that the value is a string, not non-empty or trim.
product.displayNameInternally requiredNon-empty stringInternal delivery must provide a non-empty display name; 26.7.17 provider only validates that the value is a string, not non-empty or trim.
product.envVarNoStringPreferred as the installation root environment variable; if not provided, the first environment-variable discovery name will be used.
product.exampleFolderNoString26.7.17 This hint is read but is not used to participate in directory searches.
connectorRuntime.commandWhen connectorRuntime exists, it isa non-empty stringUse ${pluginRoot} to expand and start the helper; when the command does not exist, fall back to static discovery, and other startup or output errors are recorded as invalid.
connectorRuntime.argsNoString arrayExpand with ${pluginRoot}; non-string items are filtered.
connectorRuntime.envNostring to string mappingNon-string values are filtered; value is expanded using the helper template context and then overwritten to the child process environment. The only reliable built-in variable in the default production path is ${pluginRoot}.
connectorRuntime.timeoutMsNonumberDefault 5000 ms; example explicitly set to 10000 ms.
discovery[].kindYesenvironment-variable, known-location or context-rootprovider first determines the product installation root; the static path then resolves the context root, and then renders the MCP and Skill.
environment-variable.namesInternally requiredAt least one non-empty string arrayThe provider only processes names as items in the array, and then filters non-strings and empty strings; if it is empty after filtering, there are no environment variable candidates, and an error is not necessarily reported in the reading phase.
known-location.platformInternally requiredwin32-x64Currently Windows auto-discovery must be filled in explicitly. The implementation is also compatible with windows, but the public manifest platform enumeration only contains win32-x64; when missing or does not match the current platform, the known-location item will not be selected.
known-location.searchParentsInternally requiredAn array of at least one non-empty path stringInternal deliveries must provide a standard directory probe root. 26.7.17 If it is missing or not an array, it will be normalized to []. Only non-strings will be filtered in the array, and empty strings will not be checked. An error will not necessarily be reported during the reading phase. The host test option can also cover the array. Path supports %NAME% environment variable expansion.
known-location.installDirPatternYesStringThe current implementation is based on directory name prefix matching; the trailing * is treated as a prefix wildcard hint.
known-location.requiredFilesInternally requiredAn array of at least one non-empty path stringInternal delivery and review must confirm that each item is non-empty and actually exists. 26.7.17 First check the length of the original array, and then filter non-strings; for example, [123] will become an empty list, and subsequent every([]) may pass as a true value, so the provider has not strictly blocked malformed values.

Internal delivery must independently confirm that the directory pointed to by the environment variable and the known-location candidate contain all non-empty requiredFiles; do not rely solely on the provider returning detected to determine that the installation root is safe. 26.7.17 will call validRoot to check the directory and normalized file list, but the above "check first, filter later" restriction means that this check is not a complete security boundary. Without environment variables, a known-location search only accepts the only valid candidate; zero or more candidates will remain missing and give a diagnostic. %ProgramFiles% is a searchParents-specific environment variable expansion, not a manifest MCP template variable.

context-root dynamic template variables ​

context-root only runs in static discovery paths. The provider first establishes the { installRoot, productVersion, installRootBasename } basic context, and then parses the dynamic roots item by item; only after all are successful, the dynamic variables are merged into the command / args / env / endpoint and Skill path template context of the static connector MCP. Once the helper returns a result (including missing or invalid), the context-root will not be processed and the helper JSON will no longer expand these templates.

FieldsProduct Internal Requirements26.7.17 Current Behavior
context-root.variableMatches [A-Za-z_][A-Za-z0-9_]*, unique within the same contribution, and must not overwrite installRoot, productVersion, installRootBasenameStatements that do not match regular rules are skipped; duplicates or reserved names are not checked, and the dynamic value that appears later can overwrite the previous value or even the basic key, so the internal audit must supplement the conflict check.
context-root.envNamesOptional; each trim is non-empty and non-repeatingRead the host coverage environment and process environment in order; filter non-strings and empty strings, but do not trim names. Verify immediately after encountering the first set value: if the directory is invalid, subsequent environment names or searchRoots will not be tried.
context-root.searchRootsOptional; provide at least one env name or search root; each item is a non-empty template pathFilter non-strings and empty strings, which are rendered with the base context in turn; cannot reference another dynamic context root. The first directory that satisfies the path check wins.
context-root.requiredPathsAt least one non-empty relative path after trim; confirm the real existence item by itemWhen the original array length is 0, the entire declaration is skipped; non-strings and empty strings will be filtered afterwards, but the array is not confirmed to be non-empty again, so the malformed array may degenerate into every([]). Internal review must reject such input.

The resolved root must be a directory and each requiredPaths entry must be present (either file or directory). If any accepted context-root cannot find a valid root, the entire static linker becomes invalid; only after all dynamic roots succeed will its variables be added to the MCP/Skill template context. Static providers fail strictly on unknown template variables: regardless of whether the unknown variable appears in the context-root's searchRoots, MCP or Skill, a rendering exception will make the connector invalid.

connector helper runtime and JSON output ​

When connectorRuntime.command is empty or there is no runtime object available, the provider directly uses static discovery; when the helper startup command returns ENOENT, it also falls back to static discovery. In addition, there is no "continue static detection after helper failure": non-zero exit, timeout, other startup errors, invalid JSON or invalid returned by the helper all produce invalid results; the helper returns missing / unsupported and ends in the original state without any rollback. The command and args of the helper are expanded with ${pluginRoot}; the value of connectorRuntime.env can also refer to the environment override explicitly passed to the provider by the host. 26.7.17 The helper renderer will replace unknown template variables with empty strings instead of reporting errors; this is different from the strict failure of static providers. Internal product delivery must uniformly implement stricter review: reject all undeclared variables, and must not rely on "expand to null" or the ENOENT fallback accidentally triggered by this. The child process environment is sequentially merged by the current process environment, host override and rendered connectorRuntime.env.

Helper stdout must be a single JSON object; currently the following fields are read:

FieldType or allowed valuesCurrent behavior
statusdetected, missing, invalid, unsupportedOther values or missing values are normalized to invalid.
productName, productVersionOptional stringUsed for connector and product version display; non-string discarded.
installRoot, launchFilestring or nullstring is normalized to the local path; other values are normalized to null.
launchArgsOptional array of stringsNon-string items to be filtered.
mcpServersOptional arrayNormalized according to the "Built-in Connector" table in the previous section; the helper must output the parsed command / endpoint / path and will not expand the manifest template again.
skillsOptional arrayOnly retain items with string id and path, the path will be normalized; optional display fields are displayName, description, overview, source only retains skill-frontmatter / manifest, other values default to runtime.
messageOptional stringUsed as a failure or degradation diagnostic; non-string discarded.
candidatesOptional string arrayUsed to display diagnostics such as multiple installation candidates; non-string items are filtered.

The helper's mcpServers[].tools also supports tool display metadata: each name must be trimmed and not empty, optional description and inputSchema in object form; source can be manifest, runtime, merged, otherwise press runtime. These display fields do not replace runtime tools/list detection, nor do they relax MCP's ID, transport, endpoint, or command auditing. This example will only enter the automatic discovery process after the package is placed in the host's built-in plug-in directory, packaged by the product, and loaded as source: builtin, trustLevel: host-bundled. Installing the same directory as a normal local plug-in will not promote it to a trusted connector and will not obtain automatic authorization. The connector discovered by the built-in provider cannot be uninstalled; the start-stop state and health diagnosis will still enter the confirmed state and final projection.

Security and Trust Boundary ​

  • Installation scripts and implicit host commands are prohibited: scripts, install, postinstall, preinstall, commands must not appear at any level of the list. Child processes that need to be started must be explicitly declared via an audited runtime, connectorRuntime or MCP command and consistent with permissions and trust domains.
  • Disable third-party bundled product runtime: activation.provider: product-runtime only allows built-in host-bundled plug-ins; untrusted sources will fail closed during the parsing or final projection phase.
  • Built-in trust is given by the product catalog, not self-reported by the manifest: publisher.verified: true, product ID, or placing similar fields cannot turn a local plugin into host-bundled. Only product packaging and host registration code can establish this status.
  • Path must be controlled: Icons and Skills of ordinary plug-ins must not escape the package root. The internal delivery and review of the connector must independently confirm that ${installRoot} is the expected product directory, and confirm item by item that the non-empty requiredFiles actually exists; the filtering order of 26.7.17 provider has not completely rejected the malformed list, and its validRoot result cannot be regarded as a safety guarantee for the risk of blocked paths. The manifest parser also does not currently cover all runtime paths, so integration review must be supplemented by real file and path boundary checks.
  • Declaration does not equal enforcement of isolation: resourceLimits and packageIntegrity in 26.7.17 were primarily declaration data, and the directory installer did not fully enforce these limits or digest validation. Do not lower your packaging audit requirements based on this.
  • Ordinary permissions must be confirmed by the host: list application, contribution requirement and confirmed grant are indispensable. There is currently no third-party self-service authorization process, and any integration that bypasses host confirmation is not supported.

Internal integration process ​

The fixed execution sequence is as follows:

Confirm capability type → Assign stable ID → Prepare directory → Write and parse manifest → Review runtime and permissions → Place in product Plugins directory → Package startup verification → Verify details and effective capabilities → Regression start-stop and fault behavior

Among them, "Put into the product Plugins directory" only applies to built-in packages that are to be delivered with the product. Integration verification of ordinary plug-ins can take the local installation path from the controlled directory, but because there is currently no third-party authorization UI, the host code responsible for integration must still establish a confirmed grant; the product's built-in connector must enter plugins/builtin to confirm that the entity path in the packaged product can be read by the helper and MCP.

Common rejection reasons ​

ReasonPhaseCurrent Result or Processing
Missing root directory plugin.jsonPackage validationPluginPackageValidationError: The plug-in package is missing plugin.json.
schema not supportedmanifest parsingmanifest.unsupportedSchema. Only accepts mogick.plugin.v1.
Required fields are missing or emptyManifest parsingmanifest.missingField; some nested fields are returned as manifest.invalidField.
Invalid icon pathManifest parsingNon-package relative paths or non-SVG/PNG/JPG/JPEG/WebP extensions are rejected with manifest.invalidField.
Installation script key appearsmanifest parsingmanifest.disallowedScript; check is recursive.
contributions is emptymanifest parsingmanifest.invalidField.
Duplicate contribution IDManifest parsingThe first four categories of contributions are rejected when repeated across arrays; exclusiveGroups also checks for duplication within its own array.
Unknown permission kindmanifest parsingmanifest.invalidField.
The platform does not match, or the common plug-in fills in non-empty mogickAppDesktop / pluginApicontribution admissionhost-incompatible, does not enter the valid candidate.
The required permission is not declared or confirmedcontribution permissionpermission-denied; the initial grant for ordinary local plug-ins is empty.
Normal MCP lacks top-level runtime, or stdio MCP is not runtime.kind: subprocesscontribution permissionpermission-denied; HTTP must also provide a legal runtime, and the internal specification uses kind: none.
MCP field error or duplicate MCP ID for the same contributionMCP projectionsPluginManifestMcpEntryError, the contribution's MCP is rejected with the plugin.manifest-mcp-invalid diagnostic.
MCP uses unknown template variableMCP projectionNormal manifest MCP projection fails; connector static template records status as invalid.
The plugin ID is reserved by the host's built-in directoryLocal installationplugin.reserved-id. Local packages cannot override product built-in IDs.
Submit compressed packageLocal installationplugin.archive-not-supported; currently only supports directories.

Integration Checklist ​

  • [ ] The package root directory exists and depends on only one required file: plugin.json.
  • [ ] schemaVersion is exactly mogick.plugin.v1, plugins, contributions, MCPs and Skill IDs are stable and conflict-free.
  • [ ] The ordinary plug-in ID uses the reverse domain name controlled by the team; it does not occupy the host's built-in reserved ID.
  • [ ] Icons and common plug-in Skills are located in the plug-in root directory, and the runtime entry is consistent with the actual packaging path.
  • [ ] Manifest does not contain install script keys or implicit host commands at any level.
  • [ ] contributions has at least one non-empty array; the values ​​of exclusiveGroup and requiredPermissions are non-empty and supported.
  • [ ] Ordinary stdio/HTTP MCP fields are complete and exist in the top-level runtime: stdio is subprocess, HTTP is internally specified none; template variables only use ${pluginRoot} / ${userWorkspace}.
  • [ ] Top-level declaration permissions cover all requirements of contribution and MCP; ordinary plug-ins already have host confirmed grant and audit evidence.
  • [ ] There is no product-runtime activation for third-party or generic native plugins.
  • [ ] Product connectors are only loaded in built directories with verification records as builtin / host-bundled; no publisher.verified is used to impersonate trust.
  • [ ] environment-variable.names, known-location.platform, searchParents and requiredFiles all satisfy internal forced formatting and do not rely on the provider's relaxed normalization of null or malformed arrays.
  • [ ] The variables, envNames, searchRoots, and requiredPaths of context-root have been strictly reviewed; dynamic variables have no duplication, do not overwrite basic variables, and are parsed successfully before MCP/Skill projection.
  • [ ] Connector MCP uses endpoint instead of url and does not rely on headers; the ID is non-empty and unique, and transport and isolation are explicitly legal.
  • [ ] helper command / args / env only uses audited variables; the status, path, MCP, Skills and diagnostic fields of the helper JSON are schema checked and ENOENT fallback and other errors fail closed are verified respectively.
  • [ ] Environment variable discovery and known-location discovery are tested separately; zero candidates, multiple candidates, missing files and helper failures all have expected diagnoses.
  • [ ] The MCP/Skills displayed on the details page are consistent with the results of effectiveContributions and actual tools/list.
  • [ ] Enable, disable, health degradation, process crash, restart and mutually exclusive selection behavior complete regression.
  • [ ] Use catalog installation or product packaging verification; no assumption is made that market releases, tarball installations, or third-party self-service authorizations already exist.