@uluops/registry-mcp 0.1.0 → 0.2.4
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.
- package/CHANGELOG.md +131 -4
- package/LICENSE +21 -0
- package/README.md +100 -93
- package/dist/client/sdk-error-mapper.d.ts +29 -0
- package/dist/client/sdk-error-mapper.d.ts.map +1 -1
- package/dist/client/sdk-error-mapper.js +122 -20
- package/dist/client/sdk-error-mapper.js.map +1 -1
- package/dist/config/index.d.ts +7 -1
- package/dist/config/index.d.ts.map +1 -1
- package/dist/config/index.js +91 -14
- package/dist/config/index.js.map +1 -1
- package/dist/config/tool-registry.d.ts.map +1 -1
- package/dist/config/tool-registry.js +0 -8
- package/dist/config/tool-registry.js.map +1 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +19 -6
- package/dist/index.js.map +1 -1
- package/dist/tools/batch-publish.js +8 -8
- package/dist/tools/batch-publish.js.map +1 -1
- package/dist/tools/index.d.ts +1 -1
- package/dist/tools/index.d.ts.map +1 -1
- package/dist/tools/index.js +2 -4
- package/dist/tools/index.js.map +1 -1
- package/dist/tools/{check-forkable.d.ts → is-forkable.d.ts} +1 -1
- package/dist/tools/is-forkable.d.ts.map +1 -0
- package/dist/tools/{check-forkable.js → is-forkable.js} +1 -1
- package/dist/tools/is-forkable.js.map +1 -0
- package/dist/tools/render-definition.d.ts +3 -0
- package/dist/tools/render-definition.d.ts.map +1 -1
- package/dist/tools/render-definition.js +15 -1
- package/dist/tools/render-definition.js.map +1 -1
- package/dist/tools/update-and-publish.d.ts.map +1 -1
- package/dist/tools/update-and-publish.js +22 -10
- package/dist/tools/update-and-publish.js.map +1 -1
- package/dist/tools/update-definition.d.ts.map +1 -1
- package/dist/tools/update-definition.js +2 -7
- package/dist/tools/update-definition.js.map +1 -1
- package/dist/types/config.d.ts +6 -2
- package/dist/types/config.d.ts.map +1 -1
- package/dist/utils/error-guards.d.ts +21 -0
- package/dist/utils/error-guards.d.ts.map +1 -0
- package/dist/utils/error-guards.js +26 -0
- package/dist/utils/error-guards.js.map +1 -0
- package/dist/utils/logger.d.ts.map +1 -1
- package/dist/utils/logger.js +28 -3
- package/dist/utils/logger.js.map +1 -1
- package/dist/utils/read-yaml-file.d.ts.map +1 -1
- package/dist/utils/read-yaml-file.js +16 -1
- package/dist/utils/read-yaml-file.js.map +1 -1
- package/dist/utils/tool-handler.d.ts.map +1 -1
- package/dist/utils/tool-handler.js +20 -8
- package/dist/utils/tool-handler.js.map +1 -1
- package/package.json +21 -20
- package/dist/tools/check-forkable.d.ts.map +0 -1
- package/dist/tools/check-forkable.js.map +0 -1
- package/dist/tools/sync-models.d.ts +0 -12
- package/dist/tools/sync-models.d.ts.map +0 -1
- package/dist/tools/sync-models.js +0 -32
- package/dist/tools/sync-models.js.map +0 -1
package/CHANGELOG.md
CHANGED
|
@@ -7,11 +7,136 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
|
|
7
7
|
|
|
8
8
|
## [Unreleased]
|
|
9
9
|
|
|
10
|
+
## [0.2.4] - 2026-06-07
|
|
11
|
+
|
|
12
|
+
Docs + packaging polish. Adds the standard 5-badge set to the README matching the rest of the public UluOps packages, and closes a packaging hygiene gap — the package declared `"license": "MIT"` but shipped without the LICENSE file. No behavioural change.
|
|
13
|
+
|
|
14
|
+
### Added
|
|
15
|
+
|
|
16
|
+
- LICENSE file (MIT, Copyright (c) 2026 UluOps) at the repo root. The package previously declared `"license": "MIT"` in `package.json` but the file was absent. Adding it makes the license terms reachable both from a GitHub-cloned consumer and from an unpacked npm tarball.
|
|
17
|
+
- LICENSE listed in the `files` array so it ships in the published tarball. Without this entry the LICENSE would have been added to the repo but excluded from the npm package — the same hygiene gap from a different angle.
|
|
18
|
+
|
|
19
|
+
### Changed
|
|
20
|
+
|
|
21
|
+
- README header gains the five shields.io badges (npm version, MIT license, node engine, TypeScript 5.7+, tests passing) immediately under the package name, matching the `@uluops/core` package presentation. The tagline was already present from the v0.2.3 ship; this completes the visual alignment with the rest of the public UluOps surface. Tests badge points to `src/__tests__/` (the actual test home in this repo).
|
|
22
|
+
|
|
23
|
+
## [0.2.3] - 2026-06-05
|
|
24
|
+
|
|
25
|
+
Polish release. Six tracker findings closed: documentation freshness,
|
|
26
|
+
filesystem availability + symlink hardening, src-tree naming alignment,
|
|
27
|
+
402 upgrade-URL prompt-injection guard, and 19 lint warnings removed
|
|
28
|
+
from the security-boundary module.
|
|
29
|
+
|
|
30
|
+
### Fixed
|
|
31
|
+
|
|
32
|
+
- **`readYamlFile` now wraps `realpathSync(WORKSPACE_DIR)` in a try/catch.** A typo'd `WORKSPACE_DIR` env var, an unmounted NFS path, or a fresh container where the dir hadn't been created yet previously threw an opaque `ENOENT` for the workspace root rather than the file the user actually asked about. The error message now names WORKSPACE_DIR explicitly and tells the user how to fix it.
|
|
33
|
+
- **`validateLogDir` now dereferences symlinks before the containment check (CWE-59).** A symlink at `LOG_DIR` could previously escape the cwd/`/tmp/` constraint because `resolve()` doesn't follow symlinks. Also dereferences the comparison anchors (cwd, `/tmp/`) so macOS's `/tmp` → `/private/tmp` symlink no longer breaks the legitimate `/tmp/...` case. Only active when `ENABLE_FILE_LOGGING=true`.
|
|
34
|
+
- **402 `upgradeUrl` now passes through a protocol/host guard before being embedded in MCP responses (CWE-601).** A compromised or malicious registry server could previously emit `javascript:`, `data:`, or off-domain URLs in the 402 response body, landing them in the consuming agent's context window as prompt-injection bait. The guard restricts the embedded URL to `https://` and host suffix `.uluops.ai` (or apex `uluops.ai`); anything else is dropped and the agent sees an upgrade message without a follow-able URL. Mirrors the SSRF defense in `config/index.ts`.
|
|
35
|
+
|
|
36
|
+
### Changed
|
|
37
|
+
|
|
38
|
+
- **`src/tools/check-forkable.ts` renamed to `src/tools/is-forkable.ts`.** The file registers `is_forkable` (renamed in v1.13.0 of the legacy package); the source filename was a legacy artifact. Internal-only rename — the tool name, schema, and behavior are unchanged.
|
|
39
|
+
- **19 `@typescript-eslint/strict-boolean-expressions` lint warnings cleared from `sdk-error-mapper.ts`.** The security-boundary module is now lint-clean. Every implicit truthiness check was converted to explicit `!== undefined` / `!== ''` / `=== true` form. No behavior change — but the file is now easier to reason about as code paths near credential redaction.
|
|
40
|
+
- **`isApiKey` detection in `src/index.ts` uses explicit `=== true`** for the optional-chained `startsWith('ulr_')`. Same intent as before; falls through to session-token auth when `apiKey` is undefined. Linter-friendly.
|
|
41
|
+
- **README test count updated to 348** (was stale at 329).
|
|
42
|
+
|
|
43
|
+
|
|
44
|
+
|
|
45
|
+
Hardening pass against the ship-pipeline findings. No new tools. No
|
|
46
|
+
breaking changes to existing tool contracts (the new `render_definition`
|
|
47
|
+
`overwrite` parameter defaults to `false` — agents that previously
|
|
48
|
+
silently overwrote files now receive a clear error response and need to
|
|
49
|
+
opt in).
|
|
50
|
+
|
|
51
|
+
### Fixed
|
|
52
|
+
|
|
53
|
+
- **`patchYamlVersion` now handles prerelease and build-metadata semver.**
|
|
54
|
+
The regex `\d+\.\d+\.\d+` was extended to `\d+\.\d+\.\d+(?:-[A-Za-z0-9.-]+)?(?:\+[A-Za-z0-9.-]+)?`. Previously, source YAML with `version: 1.0.0-rc.1` would leave the `-rc.1` suffix stranded after the replacement, producing malformed YAML that the API would reject. Closes the AF-006 audit trigger that was acknowledged at v0.2.0 ship time.
|
|
55
|
+
- **`update_and_publish` create-fallback now guards `created.version`.** A malformed SDK response with a missing `version` field would have been silently passed through to `publish()`, producing a `/versions/undefined` URL and a 404 for a draft that was just successfully created. The handler now throws a descriptive error if `created.version` is missing or empty.
|
|
56
|
+
- **`render_definition` no longer silently overwrites existing files.** New `overwrite: boolean` parameter (default `false`). When false (the default) and `output_path` resolves to an existing file, the tool returns a clear MCP error rather than destroying the prior content. Agents that need replacement semantics must explicitly pass `overwrite: true`.
|
|
57
|
+
- **`batch_publish` per-item errors now carry rich SDK context.** Previously each failed-item entry only carried `error` (message) and `status`. The per-item catch now routes through a new `extractErrorContext(error)` helper that surfaces 402 `upgrade_url` + `required_tier` + `current_tier`, 429 `retry_after`, and 409 `nextAvailable` exactly as single-call tools do via `mapSdkErrorToMcp`.
|
|
58
|
+
- **MCP server now auto-runs on the proper ESM entry-point check** instead of `NODE_ENV !== 'test'`. A stray `NODE_ENV=test` in the user's shell, CI, or `direnv` no longer silently disables `main()` — the harness would have started and hung waiting for stdio JSON-RPC that never arrived. Tests already import `main` directly and call it; no test changes needed.
|
|
59
|
+
|
|
60
|
+
### Changed
|
|
61
|
+
|
|
62
|
+
- **`isNumericSchema` swapped Zod `_def.innerType` access for Zod's public `unwrap()` / `removeDefault()` API.** Avoids coupling to Zod private internals that can rename across minor versions and would silently disable numeric coercion at the MCP boundary if Zod's `_def` shape ever changes.
|
|
63
|
+
- **`isPublishedStatusError` extracted to a shared `src/utils/error-guards.ts` module.** Previously this 3-line guard was duplicated verbatim across `update-definition.ts` and `update-and-publish.ts`. A future change to the underlying API error message now updates one location instead of two.
|
|
64
|
+
- **Added `prepublishOnly: npm run build` script.** Future `npm publish` runs no longer rely on the maintainer remembering to build first.
|
|
65
|
+
|
|
66
|
+
### Added
|
|
67
|
+
|
|
68
|
+
- **`extractErrorContext(error)` helper in `client/sdk-error-mapper.ts`** — returns the same structured fields (`status`, `required_tier`, `upgrade_url`, `retry_after`, `nextAvailable`) that `mapSdkErrorToMcp` produces, but without wrapping them in an MCP envelope. Used by `batch_publish`.
|
|
69
|
+
|
|
70
|
+
### Tests
|
|
71
|
+
|
|
72
|
+
348 tests pass (was 345, +3 regression coverage):
|
|
73
|
+
- New: `patches prerelease semver versions in yaml during create fallback`
|
|
74
|
+
- New: `refuses to overwrite an existing file when overwrite is not opted into`
|
|
75
|
+
- New: `writes to existing file when overwrite: true is passed`
|
|
76
|
+
|
|
77
|
+
## [0.2.1] - 2026-06-05
|
|
78
|
+
|
|
79
|
+
### Changed
|
|
80
|
+
|
|
81
|
+
- **Backend URL resolution deferred to the SDK.** Previously the MCP server
|
|
82
|
+
shadowed `@uluops/registry-sdk`'s `DEFAULT_BASE_URL` with its own copy
|
|
83
|
+
and effectively required `ULUOPS_REGISTRY_URL` (treating empty/undefined
|
|
84
|
+
as "use the shadow constant"). The SDK already resolves the correct
|
|
85
|
+
production URL (`https://api.uluops.ai/api/v1/registry`) by default and
|
|
86
|
+
switches to localhost when `NODE_ENV=development`; the MCP now passes
|
|
87
|
+
`baseUrl` through as `undefined` when the env var is unset/empty and lets
|
|
88
|
+
the SDK own URL resolution. Public consumers no longer set anything but
|
|
89
|
+
`ULUOPS_API_KEY`. README's configuration table reduced to consumer-
|
|
90
|
+
relevant variables; `ULUOPS_REGISTRY_URL` removed from the public
|
|
91
|
+
surface (still honored by the code when explicitly set).
|
|
92
|
+
- **SSRF defense and host allowlist now gate on `baseUrl !== undefined`.**
|
|
93
|
+
When the operator does not set `ULUOPS_REGISTRY_URL` the SDK uses a
|
|
94
|
+
trusted compile-time constant, so the URL-parse/allowlist/private-host
|
|
95
|
+
checks are skipped — they only run when an operator explicitly provides
|
|
96
|
+
a URL that needs validation. Identical behavior for any URL that was
|
|
97
|
+
previously accepted; previously-rejected URLs are still rejected.
|
|
98
|
+
- **Pairs with `@uluops/setup@0.6.4`** which stopped stamping
|
|
99
|
+
`ULUOPS_REGISTRY_URL` into `.mcp.json` files during onboarding, and with
|
|
100
|
+
`@uluops/ops-mcp@0.2.1` which applied the same fix to the ops tracker.
|
|
101
|
+
|
|
102
|
+
### Internal
|
|
103
|
+
|
|
104
|
+
- `DEFAULT_BASE_URL` constant removed from `src/config/index.ts`.
|
|
105
|
+
- `ApiClientConfig.baseUrl` type widened to `string | undefined`.
|
|
106
|
+
- Startup log apiUrl line shows `(SDK default)` when baseUrl is unset.
|
|
107
|
+
|
|
108
|
+
## [0.2.0] - 2026-06-05
|
|
109
|
+
|
|
110
|
+
First release of the monorepo `@uluops/registry-mcp` package at parity
|
|
111
|
+
with the standalone `uluops-registry-mcp` 0.1.1 codebase, prepared for
|
|
112
|
+
first public npm publish under the scoped name.
|
|
113
|
+
|
|
114
|
+
### Added
|
|
115
|
+
|
|
116
|
+
- **`list_languages` and `get_language` tools** — language registry
|
|
117
|
+
read tools surfaced through the MCP server.
|
|
118
|
+
|
|
10
119
|
### Changed
|
|
11
120
|
|
|
12
|
-
-
|
|
13
|
-
|
|
14
|
-
|
|
121
|
+
- **`@uluops/registry-sdk` bumped `^0.27.2` → `0.30.2`** (three minor
|
|
122
|
+
versions). Pulls in 0.29.0 publish-warning surfacing, 0.30.x sdk-core
|
|
123
|
+
security hardening cascade, and the schema-removal cleanup.
|
|
124
|
+
- **`@uluops/sdk-core` confirmed at `0.11.1`** with `redirect: 'error'`
|
|
125
|
+
on all fetch sites, control-character stripping, and widened sensitive-
|
|
126
|
+
key coverage (`x-api-key`, `set-cookie`, `proxy-authorization`).
|
|
127
|
+
- **All runtime and dev dependencies pinned to exact versions** per the
|
|
128
|
+
2026-06-01 UluOps supply-chain hardening policy.
|
|
129
|
+
- **`vitest` and `@vitest/coverage-v8` bumped to `4.1.8`** — eliminates
|
|
130
|
+
the moderate-severity esbuild advisory chained through vite. `npm audit`
|
|
131
|
+
now reports 0 vulnerabilities.
|
|
132
|
+
|
|
133
|
+
### Not included
|
|
134
|
+
|
|
135
|
+
- **`sync_models` admin tool deliberately excluded.** Calls a private
|
|
136
|
+
registry admin endpoint not exposed through the public SDK; reserved
|
|
137
|
+
for internal use and intentionally never shipped in this public package.
|
|
138
|
+
|
|
139
|
+
### Historical lineage (legacy `uluops-registry-mcp` versions below)
|
|
15
140
|
|
|
16
141
|
## [1.14.0] - 2026-05-20
|
|
17
142
|
|
|
@@ -134,7 +259,9 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
|
|
134
259
|
- Error sanitization stripping sensitive data (API keys, tokens, stack traces) from MCP responses
|
|
135
260
|
- Test suite with 194 tests covering all tools, resources, and registry config
|
|
136
261
|
|
|
137
|
-
[Unreleased]: https://github.com/Uluops/-uluops-registry-mcp/compare/
|
|
262
|
+
[Unreleased]: https://github.com/Uluops/-uluops-registry-mcp/compare/v0.2.1...HEAD
|
|
263
|
+
[0.2.1]: https://github.com/Uluops/-uluops-registry-mcp/compare/v0.2.0...v0.2.1
|
|
264
|
+
[0.2.0]: https://github.com/Uluops/-uluops-registry-mcp/releases/tag/v0.2.0
|
|
138
265
|
[1.14.0]: https://github.com/Uluops/-uluops-registry-mcp/compare/v1.13.0...v1.14.0
|
|
139
266
|
[1.13.0]: https://github.com/Uluops/-uluops-registry-mcp/compare/v1.12.0...v1.13.0
|
|
140
267
|
[1.12.0]: https://github.com/Uluops/-uluops-registry-mcp/compare/v1.11.0...v1.12.0
|
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 UluOps
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.md
CHANGED
|
@@ -1,33 +1,34 @@
|
|
|
1
|
-
|
|
1
|
+
**[UluOps](https://uluops.ai)** · Operating Intelligence as Infrastructure
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
---
|
|
4
4
|
|
|
5
|
-
|
|
5
|
+
# @uluops/registry-mcp
|
|
6
6
|
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
7
|
+
[](https://www.npmjs.com/package/@uluops/registry-mcp)
|
|
8
|
+
[](LICENSE)
|
|
9
|
+
[](https://nodejs.org)
|
|
10
|
+
[](https://www.typescriptlang.org/)
|
|
11
|
+
[](src/__tests__/)
|
|
12
|
+
|
|
13
|
+
MCP (Model Context Protocol) server for the [UluOps](https://uluops.ai) Registry API. Provides **44 tools** and **4 resources** that let Claude Code, OpenCode, Gemini CLI, and other MCP-compatible harnesses browse, create, validate, version, and analyze AI workflow definitions (agents, commands, workflows, pipelines).
|
|
12
14
|
|
|
13
|
-
|
|
15
|
+
## Quick start
|
|
14
16
|
|
|
15
|
-
|
|
17
|
+
The recommended way to install this is via [@uluops/setup](https://www.npmjs.com/package/@uluops/setup), which writes the MCP config for you:
|
|
16
18
|
|
|
17
19
|
```bash
|
|
18
|
-
|
|
20
|
+
npx @uluops/setup
|
|
19
21
|
```
|
|
20
22
|
|
|
21
|
-
|
|
23
|
+
If you'd rather wire it up by hand, add this block to your harness's MCP config (e.g. `~/.claude.json` for Claude Code, `~/.config/opencode/opencode.json` for OpenCode):
|
|
22
24
|
|
|
23
25
|
```json
|
|
24
26
|
{
|
|
25
27
|
"mcpServers": {
|
|
26
28
|
"uluops-registry": {
|
|
27
|
-
"command": "
|
|
28
|
-
"args": ["/
|
|
29
|
+
"command": "npx",
|
|
30
|
+
"args": ["-y", "@uluops/registry-mcp"],
|
|
29
31
|
"env": {
|
|
30
|
-
"ULUOPS_REGISTRY_URL": "http://localhost:3001/api/v1",
|
|
31
32
|
"ULUOPS_API_KEY": "your-api-key"
|
|
32
33
|
}
|
|
33
34
|
}
|
|
@@ -35,39 +36,35 @@ Then add to your `.mcp.json`:
|
|
|
35
36
|
}
|
|
36
37
|
```
|
|
37
38
|
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
## Design Philosophy
|
|
41
|
-
|
|
42
|
-
**Thin Client Pattern**: This MCP client contains **zero business logic**. All data processing, validation, storage, and rendering are handled by the registry API. The client's sole responsibility is protocol translation between MCP's stdio-based JSON-RPC and the backend's REST API.
|
|
39
|
+
Get an API key at [app.uluops.ai/settings/api-keys](https://app.uluops.ai/settings/api-keys), then restart your harness.
|
|
43
40
|
|
|
44
41
|
## Configuration
|
|
45
42
|
|
|
46
|
-
All configuration is passed via environment variables in the `env` block
|
|
43
|
+
All configuration is passed via environment variables in the `env` block. No `.env` file is needed.
|
|
47
44
|
|
|
48
45
|
| Variable | Description | Required | Default |
|
|
49
46
|
|----------|-------------|----------|---------|
|
|
50
|
-
| `
|
|
51
|
-
| `
|
|
52
|
-
| `ULUOPS_REGISTRY_TIMEOUT` | Request timeout (ms) | No | 30000 |
|
|
53
|
-
| `ULUOPS_REGISTRY_RETRIES` | Retry attempts | No | 3 |
|
|
54
|
-
| `LOG_LEVEL` | Logging level | No | info |
|
|
55
|
-
| `ENABLE_FILE_LOGGING` | Write logs to disk | No | false |
|
|
56
|
-
| `LOG_DIR` | Log file directory | No |
|
|
57
|
-
| `VERBOSE_LOGGING` | Verbose security decision logging | No | false |
|
|
58
|
-
| `LOG_PERFORMANCE_METRICS` | Log performance metrics | No | false |
|
|
47
|
+
| `ULUOPS_API_KEY` | API authentication key | Yes | — |
|
|
48
|
+
| `ULUOPS_ORG_SLUG` | Organization slug for scoped requests | No | — |
|
|
49
|
+
| `ULUOPS_REGISTRY_TIMEOUT` | Request timeout (ms) | No | `30000` |
|
|
50
|
+
| `ULUOPS_REGISTRY_RETRIES` | Retry attempts | No | `3` |
|
|
51
|
+
| `LOG_LEVEL` | Logging level (`error`, `warn`, `info`, `debug`) | No | `info` |
|
|
52
|
+
| `ENABLE_FILE_LOGGING` | Write logs to disk | No | `false` |
|
|
53
|
+
| `LOG_DIR` | Log file directory | No | `./logs` |
|
|
54
|
+
| `VERBOSE_LOGGING` | Verbose security decision logging | No | `false` |
|
|
55
|
+
| `LOG_PERFORMANCE_METRICS` | Log performance metrics | No | `false` |
|
|
59
56
|
| `WORKSPACE_DIR` | Base directory for `file_path` containment (CWE-22 protection) | No | cwd |
|
|
60
57
|
| `OUTPUT_BASE_DIR` | Base directory for `output_path` containment (CWE-22 protection) | No | cwd |
|
|
61
58
|
|
|
62
|
-
|
|
59
|
+
## Design philosophy
|
|
63
60
|
|
|
64
|
-
|
|
61
|
+
**Thin client pattern.** This MCP server contains **zero business logic**. All data processing, validation, storage, and rendering are handled by the registry API. The server's sole responsibility is protocol translation between MCP's stdio JSON-RPC and the backend REST API.
|
|
65
62
|
|
|
66
|
-
|
|
63
|
+
## Quick examples
|
|
67
64
|
|
|
68
|
-
|
|
69
|
-
// These are MCP tool calls — Claude Code invokes them automatically.
|
|
65
|
+
Once configured, your harness can invoke these tools through MCP:
|
|
70
66
|
|
|
67
|
+
```jsonc
|
|
71
68
|
// Browse published definitions
|
|
72
69
|
list_definitions({ "type": "agent", "status": "published", "limit": 10 })
|
|
73
70
|
|
|
@@ -77,93 +74,114 @@ get_definition({ type: "agent", name: "code-validator", include_yaml: true })
|
|
|
77
74
|
// Search across all definition types
|
|
78
75
|
search_definitions({ query: "validation", type: "agent" })
|
|
79
76
|
|
|
80
|
-
//
|
|
81
|
-
resolve_alias({ alias: "sonnet" })
|
|
82
|
-
|
|
83
|
-
// Validate YAML before publishing
|
|
77
|
+
// Validate YAML before publishing (inline or by file path)
|
|
84
78
|
validate_definition({ type: "agent", yaml: "..." })
|
|
85
|
-
|
|
86
|
-
// Or validate from a file path instead of inline YAML
|
|
87
79
|
validate_definition({ type: "agent", file_path: "/path/to/agent.yaml" })
|
|
88
80
|
|
|
89
81
|
// Create and publish a definition
|
|
90
|
-
create_definition({ type: "agent", name: "my-agent", yaml: "
|
|
82
|
+
create_definition({ type: "agent", name: "my-agent", yaml: "..." })
|
|
91
83
|
publish_definition({ type: "agent", name: "my-agent", version: "1.0.0" })
|
|
92
84
|
|
|
93
|
-
//
|
|
94
|
-
|
|
85
|
+
// One-call create-or-update-and-publish
|
|
86
|
+
update_and_publish({ type: "agent", name: "my-agent", version: "1.1.0", yaml: "..." })
|
|
95
87
|
|
|
96
|
-
// Compare versions
|
|
97
|
-
diff_versions({ type: "agent", name: "code-validator", from: "1.0.0", to: "1.1.0"
|
|
98
|
-
|
|
88
|
+
// Compare versions in three different formats
|
|
89
|
+
diff_versions({ type: "agent", name: "code-validator", from: "1.0.0", to: "1.1.0" }) // section summary
|
|
90
|
+
diff_versions({ type: "agent", name: "code-validator", from: "1.0.0", to: "1.1.0", format: "fields" }) // structural diff + suggested bump
|
|
91
|
+
diff_versions({ type: "agent", name: "code-validator", from: "1.0.0", to: "1.1.0", format: "unified" }) // git-style diff
|
|
99
92
|
|
|
100
|
-
//
|
|
101
|
-
|
|
102
|
-
|
|
93
|
+
// Analytics
|
|
94
|
+
get_effectiveness({ type: "agent", name: "code-validator", version: "1.1.0" })
|
|
95
|
+
compare_effectiveness({ type: "agent", name: "code-validator", versions: ["1.0.0", "1.1.0"] })
|
|
103
96
|
```
|
|
104
97
|
|
|
105
|
-
## Available
|
|
98
|
+
## Available tools
|
|
106
99
|
|
|
107
|
-
### Core
|
|
100
|
+
### Core tools (P0)
|
|
108
101
|
| Tool | Description |
|
|
109
102
|
|------|-------------|
|
|
110
103
|
| `list_definitions` | List definitions with filters (type, status, domain, visibility, search, tags, pagination) |
|
|
111
|
-
| `get_definition` | Get a single definition by type+name, optionally with YAML/runtime/refs |
|
|
104
|
+
| `get_definition` | Get a single definition by type + name, optionally with YAML / runtime / refs |
|
|
112
105
|
| `search_definitions` | Search definitions by keyword |
|
|
113
106
|
| `list_models` | List AI models with optional filters |
|
|
114
|
-
| `resolve_alias` | Resolve alias (e.g.
|
|
107
|
+
| `resolve_alias` | Resolve an alias (e.g. `sonnet`) to provider + modelId |
|
|
115
108
|
| `validate_definition` | Validate YAML without storing (accepts `yaml` or `file_path`) |
|
|
116
|
-
| `render_definition` | Get rendered markdown for a definition.
|
|
109
|
+
| `render_definition` | Get rendered markdown for a definition. `output_path` writes directly to a file |
|
|
117
110
|
|
|
118
|
-
### Definition
|
|
111
|
+
### Definition management (P1)
|
|
119
112
|
| Tool | Description |
|
|
120
113
|
|------|-------------|
|
|
121
114
|
| `create_definition` | Create a new draft definition (accepts `yaml` or `file_path`) |
|
|
122
|
-
| `update_definition` | Update a draft definition
|
|
115
|
+
| `update_definition` | Update a draft definition. Smart version-up: if target version is published or doesn't exist and YAML is provided, automatically creates a new draft |
|
|
123
116
|
| `publish_definition` | Publish a draft definition |
|
|
124
117
|
| `deprecate_definition` | Deprecate with reason and optional successor |
|
|
118
|
+
| `archive_definition` | Archive a deprecated definition (terminal lifecycle state) |
|
|
125
119
|
| `delete_definition` | Delete a draft (published definitions cannot be deleted) |
|
|
126
120
|
|
|
127
|
-
###
|
|
121
|
+
### Composite workflows (P1)
|
|
122
|
+
| Tool | Description |
|
|
123
|
+
|------|-------------|
|
|
124
|
+
| `update_and_publish` | Update a draft and publish it in one call. Inherits smart version-up + create fallback from `update_definition` |
|
|
125
|
+
| `batch_publish` | Publish up to 20 definition versions in one call. Continues on individual failures, returns both published and failed items |
|
|
126
|
+
|
|
127
|
+
### Versions & dependencies (P1)
|
|
128
128
|
| Tool | Description |
|
|
129
129
|
|------|-------------|
|
|
130
130
|
| `list_versions` | List all versions of a definition |
|
|
131
|
-
| `diff_versions` | Compare two versions.
|
|
131
|
+
| `diff_versions` | Compare two versions. `format`: `sections` (default), `fields` (structural + suggested bump), `unified` (git-style) |
|
|
132
132
|
| `get_dependencies` | Forward dependency graph |
|
|
133
133
|
| `get_dependents` | Reverse dependency graph |
|
|
134
134
|
| `get_execution_stats` | Execution statistics for a definition version |
|
|
135
135
|
| `list_forks` | List forks of a definition |
|
|
136
136
|
|
|
137
|
-
###
|
|
137
|
+
### Forks (P2)
|
|
138
138
|
| Tool | Description |
|
|
139
139
|
|------|-------------|
|
|
140
140
|
| `fork_definition` | Fork a definition |
|
|
141
141
|
| `is_forkable` | Check if a definition version can be forked |
|
|
142
142
|
| `get_fork_lineage` | Fork ancestry chain |
|
|
143
143
|
|
|
144
|
-
### Translation
|
|
144
|
+
### Translation (P2)
|
|
145
145
|
| Tool | Description |
|
|
146
146
|
|------|-------------|
|
|
147
147
|
| `retranslate_definition` | Retranslate with the latest translator version |
|
|
148
148
|
| `upgrade_definition` | Upgrade a definition from legacy format (accepts `yaml` or `file_path`) |
|
|
149
149
|
| `get_translator_version` | Get current translator version |
|
|
150
150
|
|
|
151
|
-
###
|
|
151
|
+
### Models & languages (P2)
|
|
152
152
|
| Tool | Description |
|
|
153
153
|
|------|-------------|
|
|
154
|
-
| `get_model` | Get specific model details by provider+modelId |
|
|
154
|
+
| `get_model` | Get specific model details by provider + modelId |
|
|
155
155
|
| `list_providers` | List AI providers |
|
|
156
156
|
| `list_aliases` | List all model aliases |
|
|
157
|
-
| `
|
|
157
|
+
| `list_languages` | List supported definition languages (ADL, CDL, WDL, PDL) |
|
|
158
|
+
| `get_language` | Get a definition language with its current JSON Schema |
|
|
158
159
|
|
|
159
|
-
### Execution &
|
|
160
|
+
### Execution & users (P2)
|
|
160
161
|
| Tool | Description |
|
|
161
162
|
|------|-------------|
|
|
162
163
|
| `record_execution` | Record a definition execution (idempotent) |
|
|
163
164
|
| `get_user` | Get public user profile |
|
|
164
165
|
| `batch_users` | Batch user lookup (max 100) |
|
|
165
166
|
|
|
166
|
-
|
|
167
|
+
### Analytics (P3)
|
|
168
|
+
| Tool | Description |
|
|
169
|
+
|------|-------------|
|
|
170
|
+
| `get_effectiveness` | Effectiveness metrics for a definition: pass rate, scores, taxonomy, health score |
|
|
171
|
+
| `get_health` | Health grade and issue profile for a definition |
|
|
172
|
+
| `get_ecosystem_overview` | Ecosystem-wide analytics overview |
|
|
173
|
+
| `get_lineage` | Lineage graph for a definition (versions + forks as a tree) |
|
|
174
|
+
| `get_evolution` | Version-over-version metrics with trend detection |
|
|
175
|
+
| `get_translation_analytics` | Versions grouped by translator version with aggregate metrics |
|
|
176
|
+
| `compare_effectiveness` | Compare effectiveness across 2–5 definition versions side-by-side |
|
|
177
|
+
| `get_diff_impact` | Structural diff combined with metric deltas between two versions |
|
|
178
|
+
|
|
179
|
+
### Session
|
|
180
|
+
| Tool | Description |
|
|
181
|
+
|------|-------------|
|
|
182
|
+
| `set_default_type` | Set (or clear) a session-level default for the `type` parameter. When set, definition tools use this type unless explicitly overridden |
|
|
183
|
+
|
|
184
|
+
## Available resources
|
|
167
185
|
|
|
168
186
|
MCP resources provide read-only access to registry data via the `registry://` URI scheme.
|
|
169
187
|
|
|
@@ -171,58 +189,47 @@ MCP resources provide read-only access to registry data via the `registry://` UR
|
|
|
171
189
|
|----------|-----|-------------|
|
|
172
190
|
| Definitions | `registry://definitions` | Published definitions (up to 100) |
|
|
173
191
|
| Models | `registry://models` | AI model catalog |
|
|
174
|
-
| Definition
|
|
192
|
+
| Definition types | `registry://definition-types` | Static list: agent, command, workflow, pipeline |
|
|
175
193
|
| Providers | `registry://providers` | AI provider list |
|
|
176
194
|
|
|
177
|
-
### Resource Usage
|
|
178
|
-
|
|
179
195
|
```typescript
|
|
180
|
-
// List published definitions
|
|
181
196
|
read_resource("registry://definitions")
|
|
182
|
-
|
|
183
|
-
// Browse available AI models
|
|
184
197
|
read_resource("registry://models")
|
|
185
|
-
|
|
186
|
-
// Get supported definition types with descriptions
|
|
187
198
|
read_resource("registry://definition-types")
|
|
188
199
|
```
|
|
189
200
|
|
|
190
|
-
## Rate
|
|
201
|
+
## Rate limiting
|
|
191
202
|
|
|
192
|
-
This
|
|
203
|
+
This server uses [mcp-secure-server](https://github.com/aself101/mcp-secure-server) with configuration tuned for typical harness usage patterns. Source of truth: `src/index.ts` (global) and `src/config/tool-registry.ts` (per-tool).
|
|
193
204
|
|
|
194
205
|
| Setting | Value | Notes |
|
|
195
206
|
|---------|-------|-------|
|
|
196
207
|
| Security level | `basic` | |
|
|
197
208
|
| Max requests/min | 120 | Global rate limit |
|
|
198
209
|
| Burst threshold | 15 | Requests within burst window |
|
|
199
|
-
| Burst window |
|
|
200
|
-
| Automation detection | Disabled |
|
|
210
|
+
| Burst window | 5000 ms | |
|
|
211
|
+
| Automation detection | Disabled | The calling harness is trusted automation |
|
|
201
212
|
|
|
202
|
-
Per-tool quotas are configured in `src/config/tool-registry.ts`. Read-heavy tools (list, get, search) allow up to 240 req/min. Write tools (create, update, publish) are 30
|
|
213
|
+
Per-tool quotas are configured in `src/config/tool-registry.ts`. Read-heavy tools (list, get, search) allow up to 240 req/min. Write tools (create, update, publish) are 30–60 req/min.
|
|
203
214
|
|
|
204
215
|
## Development
|
|
205
216
|
|
|
206
217
|
```bash
|
|
207
|
-
|
|
218
|
+
git clone git@github.com:Uluops/-uluops-registry-mcp.git
|
|
219
|
+
cd -uluops-registry-mcp
|
|
208
220
|
npm install
|
|
209
|
-
|
|
210
|
-
#
|
|
211
|
-
npm run dev
|
|
212
|
-
|
|
213
|
-
# Run tests
|
|
214
|
-
npm test
|
|
215
|
-
|
|
216
|
-
# Type checking
|
|
221
|
+
npm run build
|
|
222
|
+
npm test # 348 tests
|
|
217
223
|
npm run typecheck
|
|
218
|
-
|
|
219
|
-
# Linting
|
|
220
224
|
npm run lint
|
|
221
|
-
|
|
222
|
-
# Build for production
|
|
223
|
-
npm run build
|
|
224
225
|
```
|
|
225
226
|
|
|
227
|
+
## Requirements
|
|
228
|
+
|
|
229
|
+
- **Node.js:** ≥ 18
|
|
230
|
+
- **Platform:** Linux, macOS, or WSL2
|
|
231
|
+
- **Auth:** UluOps API key ([get one here](https://app.uluops.ai/settings/api-keys))
|
|
232
|
+
|
|
226
233
|
## License
|
|
227
234
|
|
|
228
235
|
MIT
|
|
@@ -12,6 +12,35 @@ import type { McpToolResponse } from '../types/index.js';
|
|
|
12
12
|
* and truncation.
|
|
13
13
|
*/
|
|
14
14
|
export declare const sanitizeErrorMessage: typeof sanitizeString;
|
|
15
|
+
export interface ExtractedErrorContext {
|
|
16
|
+
/** Sanitized human-readable message. */
|
|
17
|
+
message: string;
|
|
18
|
+
/** HTTP status code if available on the SDK error. */
|
|
19
|
+
status?: number;
|
|
20
|
+
/** 402-only: tier required for access. */
|
|
21
|
+
required_tier?: string;
|
|
22
|
+
/** 402-only: caller's current tier. */
|
|
23
|
+
current_tier?: string;
|
|
24
|
+
/** 402-only: definition reference. */
|
|
25
|
+
definition?: {
|
|
26
|
+
type?: string;
|
|
27
|
+
name?: string;
|
|
28
|
+
};
|
|
29
|
+
/** 402-only: upgrade URL (mcp-source-tagged). */
|
|
30
|
+
upgrade_url?: string;
|
|
31
|
+
/** 409-only: next available version hint. */
|
|
32
|
+
nextAvailable?: unknown;
|
|
33
|
+
/** 429-only: server-recommended retry delay in seconds. */
|
|
34
|
+
retry_after?: number;
|
|
35
|
+
}
|
|
36
|
+
/**
|
|
37
|
+
* Extract the same structured-error fields as `mapSdkErrorToMcp` produces,
|
|
38
|
+
* but without wrapping them in an `McpToolResponse`. Useful inside batch
|
|
39
|
+
* loops where each per-item failure should embed the rich error context
|
|
40
|
+
* (402 upgrade URL, 429 retry-after, 409 nextAvailable) into the parent
|
|
41
|
+
* response rather than producing one MCP error envelope per failure.
|
|
42
|
+
*/
|
|
43
|
+
export declare function extractErrorContext(error: unknown): ExtractedErrorContext;
|
|
15
44
|
/**
|
|
16
45
|
* Map an SDK error to an MCP tool response.
|
|
17
46
|
*
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"sdk-error-mapper.d.ts","sourceRoot":"","sources":["../../src/client/sdk-error-mapper.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAYH,OAAO,EAAE,cAAc,EAAE,MAAM,kBAAkB,CAAC;AAElD,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,mBAAmB,CAAC;AAEzD;;;;GAIG;AACH,eAAO,MAAM,oBAAoB,uBAAiB,CAAC;
|
|
1
|
+
{"version":3,"file":"sdk-error-mapper.d.ts","sourceRoot":"","sources":["../../src/client/sdk-error-mapper.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAYH,OAAO,EAAE,cAAc,EAAE,MAAM,kBAAkB,CAAC;AAElD,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,mBAAmB,CAAC;AAEzD;;;;GAIG;AACH,eAAO,MAAM,oBAAoB,uBAAiB,CAAC;AA6DnD,MAAM,WAAW,qBAAqB;IACpC,wCAAwC;IACxC,OAAO,EAAE,MAAM,CAAC;IAChB,sDAAsD;IACtD,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,0CAA0C;IAC1C,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,uCAAuC;IACvC,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,sCAAsC;IACtC,UAAU,CAAC,EAAE;QAAE,IAAI,CAAC,EAAE,MAAM,CAAC;QAAC,IAAI,CAAC,EAAE,MAAM,CAAA;KAAE,CAAC;IAC9C,iDAAiD;IACjD,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,6CAA6C;IAC7C,aAAa,CAAC,EAAE,OAAO,CAAC;IACxB,2DAA2D;IAC3D,WAAW,CAAC,EAAE,MAAM,CAAC;CACtB;AAED;;;;;;GAMG;AACH,wBAAgB,mBAAmB,CAAC,KAAK,EAAE,OAAO,GAAG,qBAAqB,CAuDzE;AAED;;;;;;;;GAQG;AACH,wBAAgB,gBAAgB,CAAC,KAAK,EAAE,OAAO,GAAG,eAAe,CAkHhE;AAED;;;GAGG;AACH,wBAAgB,gBAAgB,CAAC,KAAK,EAAE,OAAO,GAAG,eAAe,CAahE"}
|