Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 3 additions & 5 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -15,10 +15,8 @@ jobs:
node-version: '22'
cache: npm
- run: npm install --global npm@11.6.2
# `npm ci --ignore-scripts` once the pinned devtools is on the registry. Until then
# the pinned version is built from the devtools repository at this ref and checked
# against the lockfile integrity. Remove DEVTOOLS_SOURCE_REF after publication.
# `npm ci --ignore-scripts` while the pinned devtools is on the registry. While a pin is
# not published yet, the script builds it from the devtools repository at its release
# tag and checks the archive against the lockfile integrity.
- run: node scripts/install-devtools.cjs
env:
DEVTOOLS_SOURCE_REF: codex/extract-codex-plugin
- run: npm run release:check
9 changes: 5 additions & 4 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,8 +7,9 @@ and no model call. Its `mainsequence-mcp` skill lets Codex discover MainSequence
MCPs in conversation, remember a selection and use that project's tools through a bundled
MCP client.

Version **0.3.0** is the first release from this repository. Until devtools 0.2.8 the plugin
was built and published from
Version **0.3.1** bundles devtools 0.3.1, which stores a connected MCP's names with the saved
connection (see [the release notes](docs/codex-verification.md)). Version 0.3.0 was the first
release from this repository. Until devtools 0.2.8 the plugin was built and published from
[mainsequence-devtools](https://github.com/mainsequence-sdk/mainsequence-devtools) under the
name `mainsequence-devtools` ([ADR 0003 there](https://github.com/mainsequence-sdk/mainsequence-devtools/blob/main/docs/adr/0003-codex-plugin-extraction.md)).
The shared implementation is still that package; this repository owns the hook adapter, the
Expand Down Expand Up @@ -109,14 +110,14 @@ results. `tests/dependency-boundary.test.cjs` forbids private devtools imports.
recorded in `package-lock.json`. While that version is not published yet, run

```sh
node scripts/install-devtools.cjs /path/to/dev-mainsequence-devtools-0.3.0.tgz
node scripts/install-devtools.cjs /path/to/dev-mainsequence-devtools-0.3.1.tgz
```

with the archive from `npm pack` of the devtools release branch, or without an argument to
build it from the devtools repository at `DEVTOOLS_SOURCE_REF` (default `v<pinned version>`).
Either way the archive must match the lockfile integrity, and the registry pin is not
changed (`scripts/use-local-devtools.cjs`). CI does the same until the version is
published. After publication, confirm that `npm view @dev-mainsequence/devtools@0.3.0
published. After publication, confirm that `npm view @dev-mainsequence/devtools@0.3.1
dist.integrity` equals the lockfile entry before tagging a release; if the registry archive
differs, update the lockfile and rebuild so `build-info.json` records the published
integrity.
Expand Down
37 changes: 37 additions & 0 deletions docs/codex-verification.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,42 @@
# Codex plugin verification

## 0.3.1 — devtools 0.3.1: MCP names stored with saved connections (2026-10-22)

The plugin bundles [devtools 0.3.1](https://github.com/mainsequence-sdk/mainsequence-devtools/pull/15)
in place of 0.3.0; the hook adapter, manifest, hooks and skills are otherwise unchanged, so
the hook definition and its trusted hash are the same as in 0.3.0.

What the new devtools changes for this plugin:

- `mcp-add` resolves the release's name, its repository's name and its repository branch
and stores them with the saved connection in the shared `mcp-connections.json` as `name`,
`display_name` and `code_repository_branch_uid`. A label that cannot be read is left out;
it never makes a working MCP unavailable.
- `mcp-list` returns the stored labels without a backend request. A connection saved by an
earlier version is completed by the first listing that can read its labels. `mcp-add`,
`mcp-tools` and `mcp-call` results carry them on their connection, and discovery rows pass
the directory's `name` and `code_repository_branch_uid` through.
- The connections file is shared with the Claude Desktop plugin (0.4.18 pins the same
devtools), so a connection labelled by either host is labelled for both.
- The readable `/ms` output labels the new fields (`Release ID`, `Name`, `Repository`,
`Repository branch ID`); `--json` passes the rows to the `mainsequence-mcp` skill unchanged.

Package checks under Node 22.22.0 and npm 10.9.4, `npm run release:check`: type-check, build
from the registry archive of devtools 0.3.1 (`npm ci --ignore-scripts`; its integrity in
`package-lock.json` and `build-info.json` is the registry's `dist.integrity`), the Node tests
including a new case for the stored MCP connection labels in readable and `--json` output, release metadata, the standalone
archive and the npm archive exercised as Codex installs it. Since the pinned devtools is on
the registry, CI no longer names a devtools source branch; `scripts/install-devtools.cjs`
falls back to the pin's release tag only for an unpublished pin.

Installed-host checks with the Codex CLI 0.163.0 on macOS, in isolated `CODEX_HOME`
directories, the only model endpoint being the counted loopback fixture: `npm run
verify:codex` against this build installed from `artifacts/local-marketplace` and trusted
(`skills/list` and `hooks/list` as recorded for 0.3.0; all 13 prompt cases and both sync
cases behaved as in the 0.3.0 table below, with zero real model requests), and
`npm run verify:codex:reload` (same three results as for 0.3.0). The hook definition did
not change, so its trusted hash is still `sha256:8935862c…`.

## 0.3.0 — extraction from devtools and rename to `mainsequence` (2026-10-21)

The plugin moved out of [mainsequence-devtools](https://github.com/mainsequence-sdk/mainsequence-devtools)
Expand Down
2 changes: 1 addition & 1 deletion docs/conversational-mcp.md
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@ If no developer session exists, use the existing Main Sequence hosted login. A c

Connection metadata lives in mcp-connections.json beside the existing MainSequence CLI configuration, separated by backend and release UID. Reads/calls recheck release access and fetch the current tool catalog. A changed endpoint requires an explicit add again. Removing a connection does not revoke your login.

The release UID identifies a connection. Its optional `name` is a display label from discovery; release detail responses omit it. Adding a connection and reading or calling its tools work without that label, including for saved connections. UID-based operations do not repeat discovery to obtain a name.
The release UID identifies a connection. Since devtools 0.3.1, mcp-add also reads the release's name, its repository's name and its repository branch from the release directory and stores them with the connection as `name`, `display_name` and `code_repository_branch_uid`, so mcp-list labels a saved connection without a backend request; a connection saved by an earlier version is completed by the first listing that can read those labels, and a label that cannot be read is left out rather than making the MCP unavailable. Adding a connection and reading or calling its tools work without the labels, and UID-based operations do not repeat discovery to obtain a name. Discovery rows carry `name` and `code_repository_branch_uid` as the platform directory reports them.

Project tools enforce their ordinary permissions. The client adds no agent-specific allowlist or exclusions.

Expand Down
2 changes: 1 addition & 1 deletion manifests/codex/.codex-plugin/plugin.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "mainsequence",
"version": "0.3.0",
"version": "0.3.1",
"description": "Use MainSequence project MCPs from conversation and run explicit developer commands with the bundled runner.",
"author": {
"name": "MainSequence"
Expand Down
2 changes: 1 addition & 1 deletion manifests/codex/skills/mainsequence-mcp/SKILL.md
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ This workflow uses a client inside the plugin. Saved project connections can be
- For "which MCPs are available?", execute the runner with mcp-discover --json. It calls resource_release.mcp_endpoints on the platform MCP. Use --search TEXT, --limit N (up to 100), and --offset N when needed; count reports the full matching collection.
- Show names, release UIDs and Environment UIDs where needed to distinguish results. Discovery alone does not authorize adding every result.
- For "add metatable-mcp", identify the exact discovered release. If the name identifies multiple releases, ask which one. Execute mcp-add --uid RELEASE_UUID --json. Success means initialization and tool discovery succeeded and the connection was saved. Use the returned tool catalog immediately.
- For saved connections, execute mcp-list --json. This is local metadata, not a live health report; do not rediscover the whole directory every time the user wants to use one.
- For saved connections, execute mcp-list --json. This is local metadata, not a live health report; do not rediscover the whole directory every time the user wants to use one. Each row carries the release UID with the saved name, display_name (the repository's name) and code_repository_branch_uid when they were readable; use them to label a connection instead of discovering again.
- When asked to remove a saved connection, execute mcp-remove --uid RELEASE_UUID --json. This does not revoke the Main Sequence login.

All commands accept --backend URL. Use the endpoint already selected for the task; absent an explicit selection, the runner uses the process endpoint, current directory's endpoint, saved CLI configuration, then the standard backend. Connections are separated by backend and release UID. Do not guess or construct project URLs.
Expand Down
12 changes: 6 additions & 6 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

4 changes: 2 additions & 2 deletions package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "@dev-mainsequence/codex-plugin",
"version": "0.3.0",
"version": "0.3.1",
"description": "MainSequence plugin for Codex: /ms developer commands executed before inference and conversational project MCPs",
"license": "MIT",
"engines": {
Expand Down Expand Up @@ -36,7 +36,7 @@
"release:check": "npm run typecheck && npm test && node scripts/check-release.cjs && node scripts/pack-codex.cjs && npm pack --ignore-scripts --pack-destination artifacts && npm run verify:package"
},
"dependencies": {
"@dev-mainsequence/devtools": "0.3.0"
"@dev-mainsequence/devtools": "0.3.1"
},
"devDependencies": {
"@types/node": "18.19.130",
Expand Down
1 change: 1 addition & 0 deletions src/hosts/codexPresentation.ts
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,7 @@ const fieldNames: Record<string, string> = {
dryRun: 'Preview only', endpointOnly: 'Credentials excluded from project files', dependenciesInstalled: 'Dependencies installed',
updateAvailable: 'Update available', updateSupported: 'Automatic update supported', dependencyType: 'Dependency type',
registryPublicationVerified: 'Registry publication verified', sourceStatus: 'Source version lookup', hint: 'Note',
resource_release_uid: 'Release ID', display_name: 'Repository', code_repository_branch_uid: 'Repository branch ID',
};
const hiddenFields = new Set(['gitCommonDir', 'repositoryIdentity', 'ref', 'store', 'sourceUrl', 'dependencyPolicy', 'releaseChannel']);
const values: Record<string, string> = { python: 'Python', vite_react: 'React + Vite', available: 'Available', unavailable: 'Unavailable', unsupported: 'Unsupported', current: 'Up to date', update_available: 'Update available', not_installed: 'Not installed' };
Expand Down
7 changes: 7 additions & 0 deletions tests/codex.test.cjs
Original file line number Diff line number Diff line change
Expand Up @@ -151,6 +151,13 @@ test('Codex repository, session and project results show useful fields without J
assert.match(sdk.reason, /Registry publication verified: No/);
const structured = await handleCodexPrompt({ prompt: '/ms repositories --json' }, async () => ({ schemaVersion: 1, action: 'repositories', status: 'success', summary: 'repositories completed.', data }));
assert.deepEqual(JSON.parse(structured.reason).data, data);
// devtools 0.3.1 stores the release name, the repository name and its branch with a saved MCP connection.
const connection = { backend: 'https://fixture.example', resource_release_uid: '0c7a1a2e-6d7c-4a4e-8d2e-1f3b5c7d9e01', name: 'metatable-mcp', display_name: 'Research', code_repository_branch_uid: '7d9e0c7a-1a2e-4d7c-9a4e-8d2e1f3b5c7d', mcp_connection: { url: 'https://mcp.example/mcp', transport: 'streamable-http' } };
const added = await handleCodexPrompt({ prompt: '/ms mcp-add --uid 0c7a1a2e-6d7c-4a4e-8d2e-1f3b5c7d9e01' }, async () => ({ schemaVersion: 1, action: 'mcp-add', status: 'success', summary: 'MCP connection verified and saved.', data: { connection, tools: [] } }));
assert.match(added.reason, /Connection\n Backend: https:\/\/fixture\.example\n Release ID: 0c7a1a2e-6d7c-4a4e-8d2e-1f3b5c7d9e01\n Name: metatable-mcp\n Repository: Research\n Repository branch ID: 7d9e0c7a-1a2e-4d7c-9a4e-8d2e1f3b5c7d\n/);
assert.doesNotMatch(added.reason, /display_name|code_repository_branch_uid|resource_release_uid|\{|\}/);
const savedList = await handleCodexPrompt({ prompt: '/ms mcp-list --json' }, async () => ({ schemaVersion: 1, action: 'mcp-list', status: 'success', summary: 'Saved MCP connections for this backend.', data: [connection] }));
assert.deepEqual(JSON.parse(savedList.reason).data, [connection], 'the stored labels reach the mainsequence-mcp skill unchanged');
});

test('a literal --json option value does not request JSON output', async () => {
Expand Down
Loading