@50arms/platform-mcp 0.1.438 → 0.1.440
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/README.md +2 -2
- package/dist/design-screenshot.js +2 -2
- package/dist/docs-tools.js +2 -2
- package/dist/index.js +10 -11
- package/dist/machine-toolkit.js +1 -1
- package/dist/plugin-publish.js +2 -2
- package/dist/route-board-scope.generated.js +3 -0
- package/dist/tool-access.js +1 -1
- package/package.json +3 -3
package/README.md
CHANGED
|
@@ -50,8 +50,8 @@ All exposed as `mcp__platform__<name>` once wired through the workspace `mcp.tem
|
|
|
50
50
|
| `50arms_api_spec` | `{endpoints}` (comma-joined `METHOD /path` list, required, min 1). Returns the exact OpenAPI contract for those routes — call this when you know the route but not its exact request/response shape. |
|
|
51
51
|
| `attach_file` | `{target?, card_id, path, replaces?, primary?, filename?, content_type?}` — the server reads the LOCAL file at `path` (absolute, `/tmp/a.png` or `C:\x\a.png`) and uploads it, so its bytes never pass through the agent's context. `replaces: <attachment id>` swaps that attachment's file in place (`PUT /api/issues/:id/attachments/:aid`: same id, name and cover flag) instead of adding one; `primary: true` makes it the card's single cover, atomically with the write. Reply: `{issue: <compact row>, attachment_id, url, thumbnail_url, is_primary}`. `target: "inline_image"` (DX-5241) instead uploads a local png/jpg/gif/webp/avif (25 MB, no SVG) to `POST /api/uploads/images` with no card, takes only `path`, and replies `{url, markdown}` for embedding in any markdown body such as a `POST /api/feedback` body. Shown to a key holding `cards.edit` (DX-4523); a dispatch profile still receives it only when its catalog selection names it (`slack-agent` and `work`, DX-4386, through `extraTools`). A screenshot of browser-visible work: first `primary: true`, then `replaces` at each milestone. |
|
|
52
52
|
| `mini_app_publish` | `{target: {repo?, name}, dir, note, destination: {kind: "card_design", card_id, design_no | design_title + design_element}}` — builds a page with the repo's OWN mini app and publishes it as a revision of one of an existing card's designs, or as a new design on it (DX-5294, replacing `design_publish`; DX-4077, DX-5164, DX-5193). A card holds several designs: pass exactly one of `destination.design_no` (add a revision to that design, `POST /api/issues/<card>/designs/<no>/revisions`) or `destination.design_title` (start a new design, `POST /api/issues/<card>/designs`; the title is fixed for good), both-or-neither is refused before anything is built; `destination.design_element` (DX-5856) is required with `design_title` and refused with `design_no`: it names the one thing the design decides ("Indicator pill") and is sent as `element`, and the design joins that element's open design problem or opens one (a card has one open design problem per element); the answer carries `{card_id, design_no, revision_no, dashboard_url, local_html_path, screenshot}`. `target.name` names one of the repo's mini app targets, read from the dashboard (`GET /api/repos/<repo>`, `mini_app_targets`, edited in Settings > Board > General), never from a file; `target.repo` (a repo's name) defaults to the repo of the card's board (`GET /api/boards/<board>`) and names another repo's mini app (danxbot's own) when given. A target is `{name, command}`: a build `command` (an argument list, run in the repo root with NO shell: a bare program name, then a committed repo-relative script, then its own arguments). For each build the tool makes a fresh empty folder in the OS temp area (never inside the repo) and runs the command with the design folder's repo-relative path (forward slashes) and that output folder (absolute) appended as its LAST TWO arguments; the command writes `index.html`, one `.js` and one `.css` into it, the tool reads them and deletes the folder, so two builds never share a folder, nothing in the person's checkout is ever deleted, and no leftover output can exist. The command runs in a short-lived child process with a 5-minute limit, so the server never holds the design's checkout files open (DX-4727); once the process exits its pipes get 2 s to close, then the call stops waiting and a leftover child is killed on POSIX only (its process group; on Windows `taskkill /T` cannot reach an orphan whose parent has exited, so it may keep running); the command's own output comes back verbatim when it fails (only its last 1 MiB is kept, and the message says so when it was cut), and nothing is read or posted then. Refused before anything is built or posted, naming the target and field: a program with a path separator or whitespace, an unsafe script path (a `..` segment, a backslash, an absolute path or a drive letter), a `.cmd`/`.bat` shim on Windows (`npm`, `npx`, `yarn`, `pnpm`: name `node` and a committed script), a script that is not tracked by git or has changes against HEAD (the named script only, not what it imports), and a design folder that is tracked by git or not ignored by it. The page is written to `<tmpdir>/danx-design/<build-id>.html` before the upload, the revision carries `design_dir` (the folder, repo-relative) and the folder's text files as `source_files`, and a 1280x800 screenshot is taken when Playwright resolves from the repo or this server's cwd (`screenshot: "none: <reason>"` otherwise, never a failed publish). A new design may carry `problem_statement`, `problem_summary` and `problem_context` (DX-6000): the designer's own text for the element's design problem, REQUIRED by the server when the publish opens that problem (the card has no open design problem for that element: its first design, or the first after one was chosen) and refused when it adds a design to an open one; the tool passes them verbatim and judges nothing. `destination.card_id` is required and names an existing card (any but an Epic or Feature); the tool never creates a card, and a refused revision comes back verbatim with the `card_id`. Shown to a key holding `cards.edit`; opt-in, so a dispatch profile receives it only when its catalog selection names it (none does yet). |
|
|
53
|
-
| `plugin_publish` | `{dir, plugin, note, name?}` — builds a card-type plugin project with its own `npm run build` in a short-lived child process, archives its source (`source.tar.gz`: git-tracked plus untracked-unignored files, else what the top-level `.gitignore` leaves, minus `node_modules`, `.git`, `dist`; never `.env*`; a lockfile is required) and uploads both as a new revision of the plugin `plugin` (created on the first publish), `POST /api/plugins/<id>/revisions` (DX-5237). The build, archive and upload are `@
|
|
54
|
-
| `docs_search` | `{source, query, limit?}` — searches a docs root with the shared `@
|
|
53
|
+
| `plugin_publish` | `{dir, plugin, note, name?}` — builds a card-type plugin project with its own `npm run build` in a short-lived child process, archives its source (`source.tar.gz`: git-tracked plus untracked-unignored files, else what the top-level `.gitignore` leaves, minus `node_modules`, `.git`, `dist`; never `.env*`; a lockfile is required) and uploads both as a new revision of the plugin `plugin` (created on the first publish), `POST /api/plugins/<id>/revisions` (DX-5237). The build, archive and upload are `@50arms/plugin-sdk/publish`, the code `danx-plugin publish` runs too. The answer carries `{plugin, plugin_id, revision_id, revision_no, approval_url, screenshot}`; `approval_url` is Settings > Plugins, where a team admin approves the revision. A 1280x800 screenshot of the plugin's own render is taken when Playwright resolves from the project or this server's cwd: a headless browser opens the dashboard's public `/plugin-preview` page, which draws the built plugin's `CardView` on the app's own runtime (React, `@50arms/ui`, the card kit) with a sample card, the build served from memory so nothing is uploaded first, and the capture waits until the page reports `ready` (`screenshot: "none: <reason>"` when there is no browser, the dashboard predates the page, or the plugin fails to render; never a failed publish). A refused upload comes back verbatim with the `step` refused. Shown to a key holding `plugins.publish`; opt-in like `mini_app_publish`. |
|
|
54
|
+
| `docs_search` | `{source, query, limit?}` — searches a docs root with the shared `@50arms/docs` engine and answers `{query, results: [{id, type, title, summary, file, bytes, lines, look_in?}]}`, best first, **never a page body** (DX-5582). `source` is `{kind: "local"}` (this checkout's `docs/pages`, the server's cwd), `{kind: "dir", path}` (another docs root on this machine) or `{kind: "remote", repo}` (`repo` is the repo's name; a team repo's hosted docs, `GET /api/docs/<repo>/search`, `docs.view`, the repo must be on the caller's team's boards) or `{kind: "product"}` (50 Arms' own product docs, which every team reads, `GET /api/product-docs/search`; a repo can be named `danxbot` and is still an ordinary repo). A local or dir `file` is an absolute path; a remote `file` is the page's path inside that repo's docs. `bytes` and `lines` let the agent read the file whole or with offset/limit. A remote search validates the repo's docs strictly (422 when a page is invalid), while a local or dir search skips files it cannot read or parse and reports how many as `skipped_files` (DX-5597). A whitespace-only query is refused 400 for every source. Shown to a key holding `docs.view`; opt-in like `plugin_publish`. |
|
|
55
55
|
| `docs_read` | `{source, id}` — answers `{id, path, bytes, lines}`: the page as a file on this machine, never its text. A local or dir page is read where it is (nothing copied); a remote page is fetched from `GET /api/docs/<repo>/pages/<id>` and written to `<tmp>/danx-docs/<repo>/<id>.md`, and a product page from `GET /api/product-docs/pages/<id>` to `<tmp>/danx-product-docs/<id>.md` (named by the requested id, written under a temp name and renamed into place), replaced on every call. The agent then reads it with its own file tools. An unknown id is refused with the nearest ids. Same gate and opt-in as `docs_search` (DX-5582). |
|
|
56
56
|
| `request_permission` | `{permissions, reason}` — asks a person to grant this key ONE MORE permission (see "Asking for one more permission" above). Answers at once with the approval URL and confirm code; the grant is picked up in the background. |
|
|
57
57
|
|
|
@@ -17,12 +17,12 @@ export const SCREENSHOT_HEIGHT = 800;
|
|
|
17
17
|
export const MAX_SCREENSHOT_BYTES = 1024 * 1024;
|
|
18
18
|
/** How long a loaded page may take to say it mounted (`danx-design:ready`) before the capture goes ahead anyway. */
|
|
19
19
|
const READY_WAIT_MS = 5000;
|
|
20
|
-
/** The message a design's harness posts when it has mounted (`DESIGN_FRAME_READY` in `@
|
|
20
|
+
/** The message a design's harness posts when it has mounted (`DESIGN_FRAME_READY` in `@50arms/ui`, restated: this package cannot import it). */
|
|
21
21
|
export const READY_MESSAGE = "danx-design:ready";
|
|
22
22
|
const READY_LISTENER = `window.__danxDesignReady = false; window.addEventListener("message", function (e) { ` +
|
|
23
23
|
`if (e.data && e.data.type === ${JSON.stringify(READY_MESSAGE)}) window.__danxDesignReady = true; });`;
|
|
24
24
|
/**
|
|
25
|
-
* DX-5350: the screenshot renders the page outside `SandboxedFrame`, so `window.danxMiniApp` (which the frame injects, `@
|
|
25
|
+
* DX-5350: the screenshot renders the page outside `SandboxedFrame`, so `window.danxMiniApp` (which the frame injects, `@50arms/ui` 27.0.0)
|
|
26
26
|
* is restated here as a stub: `holdReady`, a once-only `ready` and ready-on-`load` unless held, posting the same ready message the listener
|
|
27
27
|
* above hears. `reportError` and `onAppearance` are no-ops so a harness never throws.
|
|
28
28
|
*/
|
package/dist/docs-tools.js
CHANGED
|
@@ -10,7 +10,7 @@
|
|
|
10
10
|
* read answers the path of a file on THIS machine and its size, and the agent reads it with its own file tools (Read with offset/limit,
|
|
11
11
|
* grep). That is what `50arms_api` cannot do: it answers into context and cannot write a local file.
|
|
12
12
|
*
|
|
13
|
-
* The ranking is one engine (`@
|
|
13
|
+
* The ranking is one engine (`@50arms/docs` `search.ts`): in-process for local and dir, on the dashboard for remote and product. A local or dir
|
|
14
14
|
* answer's `file` is an ABSOLUTE path, usable as it stands; a hosted answer's `file` is the page's path inside its docs, and
|
|
15
15
|
* `docs_read` is what brings it to disk. A hosted page is written to `<tmp>/danx-docs/<repo>/<id>.md` (`<tmp>/danx-product-docs/<id>.md`), replaced on every read, so the
|
|
16
16
|
* agent never reads a stale copy and re-reads of one page share one path. The file is written under a temp name and renamed into place
|
|
@@ -20,7 +20,7 @@ import { statSync } from "node:fs";
|
|
|
20
20
|
import os from "node:os";
|
|
21
21
|
import path from "node:path";
|
|
22
22
|
import { z } from "zod";
|
|
23
|
-
import { MAX_SEARCH_LIMIT, UnknownNodeIdError, loadLocalDocs, locateLocalPage, searchLocalDocs } from "@
|
|
23
|
+
import { MAX_SEARCH_LIMIT, UnknownNodeIdError, loadLocalDocs, locateLocalPage, searchLocalDocs } from "@50arms/docs/agent";
|
|
24
24
|
import { repoNameArgSchema } from "./board-id.js";
|
|
25
25
|
import { writeFileDurable } from "./durable-write.js";
|
|
26
26
|
/** The tools' shared `source` argument (one flat object so the schema stays plain: `path` goes with `dir`, `repo` with `remote`; `sourceProblem` enforces it). */
|
package/dist/index.js
CHANGED
|
@@ -109,7 +109,7 @@ import { miniAppRestore } from "./mini-app-restore.js";
|
|
|
109
109
|
import { pluginPublish } from "./plugin-publish.js";
|
|
110
110
|
import { docsRead, docsSearch, docsSourceShape } from "./docs-tools.js";
|
|
111
111
|
import { spillRoleInstruction } from "./role-instruction-file.js";
|
|
112
|
-
import { DEFAULT_LIMIT, MAX_SEARCH_LIMIT } from "@
|
|
112
|
+
import { DEFAULT_LIMIT, MAX_SEARCH_LIMIT } from "@50arms/docs/agent";
|
|
113
113
|
import { boundedResultText } from "./result-limit.js";
|
|
114
114
|
import { bodyValueSchema, queryValueSchema } from "./types.js";
|
|
115
115
|
import { termsAcceptanceCallHalt, termsHaltFor } from "./terms-halt.js";
|
|
@@ -810,9 +810,9 @@ strictTool("mini_app_restore", "Write a design revision's stored source back to
|
|
|
810
810
|
// ---------------- plugin_publish (DX-5237, parent DX-4679) ----------------
|
|
811
811
|
//
|
|
812
812
|
// Agent-specific like mini_app_publish: it builds in the agent's OWN checkout (`npm run build` in a short-lived child process) and uploads the
|
|
813
|
-
// result, which the dashboard cannot do. The build, archive and upload are `@
|
|
813
|
+
// result, which the dashboard cannot do. The build, archive and upload are `@50arms/plugin-sdk/publish`, shared with the `danx-plugin`
|
|
814
814
|
// CLI; the screenshot is this tool's alone. Opt-in for the same reason as mini_app_publish (`tool-defs.ts`'s `MCP_SERVER_OPT_IN_TOOLS`).
|
|
815
|
-
strictTool("plugin_publish", "Build a card-type plugin project (Vite, `danxPlugin()` from `@
|
|
815
|
+
strictTool("plugin_publish", "Build a card-type plugin project (Vite, `danxPlugin()` from `@50arms/plugin-sdk/vite`, a lockfile) with its own `npm run build` and publish it as a new revision of the team's plugin " +
|
|
816
816
|
"`plugin` (a new key creates it): uploads `dist/`, the source `.tar.gz` and a screenshot of the plugin's own render (its `CardView` drawn with a sample card on the dashboard's `/plugin-preview` page). " +
|
|
817
817
|
"Returns `{ok: true, status, body: {plugin, plugin_id, revision_id, revision_no, approval_url, screenshot}}`: `approval_url` is Settings > Plugins, where a team admin approves the revision; you cannot. " +
|
|
818
818
|
"`screenshot` is `captured` or `none: <reason>` (the publish still succeeds). A build error throws with the build's output; a refused upload comes back verbatim as `{ok: false, status, body, plugin, step}`.", {
|
|
@@ -826,7 +826,7 @@ strictTool("plugin_publish", "Build a card-type plugin project (Vite, `danxPlugi
|
|
|
826
826
|
// One pair of tools over three places a docs root lives (`source`): this checkout's `docs/pages`, another local docs root, or a team repo's hosted
|
|
827
827
|
// docs on the dashboard. They answer with file paths and sizes, never page text (`docs-tools.ts`): `50arms_api` answers into context and cannot write
|
|
828
828
|
// the local file a remote page is read from. Opt-in like `plugin_publish` (`tool-defs.ts`'s `MCP_SERVER_OPT_IN_TOOLS`).
|
|
829
|
-
strictTool("docs_search", "Search docs with the shared @
|
|
829
|
+
strictTool("docs_search", "Search docs with the shared @50arms/docs engine. Returns `{query, results: [{id, type, title, summary, file, bytes, lines, look_in?}]}`, best first, never a page body; " +
|
|
830
830
|
"then `docs_read` the id you pick. `file` is an absolute path for local/dir and the page's path in the repo's docs for remote; `bytes`/`lines` size it for offset/limit reads.", {
|
|
831
831
|
source: docsSourceShape,
|
|
832
832
|
query: z.string().min(1).describe("A question or the words a page would use."),
|
|
@@ -881,14 +881,13 @@ strictTool("plan_connect",
|
|
|
881
881
|
"(show the code, open the URL, then call again; it waits until this session ends; a call re-asks an expired one). " +
|
|
882
882
|
"Signed in, the reply carries `owedComments` (person comments no agent has answered yet: read first, answer each, ack then reply) and `missedEvents` (operator " +
|
|
883
883
|
"events no session had been told about: read next), " +
|
|
884
|
-
"`browserInstruction` (do it now), `briefing` (
|
|
884
|
+
"`browserInstruction` (do it now), `briefing` (goals, rules, caveats, architecture " +
|
|
885
885
|
"titles and a first page of open cards) and `listenerHealth` (when its `state` is not `healthy`, do its " +
|
|
886
|
-
"`nextStep`). A session is on at most one plan: connecting elsewhere moves it (`movedFrom` names the " +
|
|
887
|
-
"plan it left). A plan holds one live session:
|
|
888
|
-
"
|
|
889
|
-
"
|
|
890
|
-
"
|
|
891
|
-
"No agent to sign in as: `agent_needed` (none exists for you; propose one) or `agent_limit_reached` (the member's or team's cap on sessions signed in as an agent is full; the person ends another session or raises the cap), nothing connects: follow its `instruction`, " +
|
|
886
|
+
"`nextStep`), and `docsLandJob` (on a docs land assignment: the conflict job's text, or `unavailable` with why). A session is on at most one plan: connecting elsewhere moves it (`movedFrom` names the " +
|
|
887
|
+
"plan it left). A plan holds one live session: another on it refuses the connect (`plan_has_live_session`, " +
|
|
888
|
+
"naming that session); do not retry: tell the person and connect elsewhere. A session whose plan another took while it was quiet is refused its next `/api/plans/mine/...` call: connect elsewhere or ask the person. Afterwards `50arms_api` calls to `/api/plans/mine/...` act on this plan, no plan id. " +
|
|
889
|
+
"Connecting signs you in as a team agent (`agent`, `agentInstruction`). " +
|
|
890
|
+
"No agent to sign in as: `agent_needed` (none exists for you; propose one) or `agent_limit_reached` (the cap on agent sessions is full; the person ends another or raises it), nothing connects: follow its `instruction`, " +
|
|
892
891
|
"no other dashboard work until `plan_connect` holds an agent. A `naming` block (status `needed`) gives the exact " +
|
|
893
892
|
"`title`, `{Name}: PLAN-NNN {short title}`; rename this thread to it (`set_session_title`, or ask for `/rename`), then connect again with that `title`. " +
|
|
894
893
|
// DX-4608 / DX-5549: a title in the format naming another agent than the held one is refused.
|
package/dist/machine-toolkit.js
CHANGED
|
@@ -250,7 +250,7 @@ function resolveToolkitVersion(stamped, readManifest) {
|
|
|
250
250
|
return stamped ?? readManifest();
|
|
251
251
|
}
|
|
252
252
|
var readOwnManifest = () => JSON.parse(readFileSync2(new URL("../../package.json", import.meta.url), "utf8")).version;
|
|
253
|
-
var TOOLKIT_VERSION = resolveToolkitVersion(false ? void 0 : "0.1.
|
|
253
|
+
var TOOLKIT_VERSION = resolveToolkitVersion(false ? void 0 : "0.1.440", readOwnManifest);
|
|
254
254
|
function envelope(now) {
|
|
255
255
|
return { contract_version: CONTRACT_VERSION, toolkit_version: TOOLKIT_VERSION, profile: PROFILE, measured_at: now.toISOString() };
|
|
256
256
|
}
|
package/dist/plugin-publish.js
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
* DX-5237 (DX-4679 section 6) - the `plugin_publish` flow: build a card-type plugin project with its own `npm run build`, archive its source,
|
|
3
3
|
* take a screenshot, and upload all of it as a revision of one of the team's plugins (created on the first publish).
|
|
4
4
|
*
|
|
5
|
-
* The build, the archive and the upload are `@
|
|
5
|
+
* The build, the archive and the upload are `@50arms/plugin-sdk/publish`, the same code the `danx-plugin publish` CLI runs; this module adds
|
|
6
6
|
* what only an agent's tool has: the dashboard client it already holds (its credential, trace and session headers) as the transport, and the
|
|
7
7
|
* screenshot: the built plugin's own render on the dashboard's `/plugin-preview` page (`plugin-screenshot.ts`, DX-5256). No browser, a dashboard
|
|
8
8
|
* without that page or a failed render publishes WITHOUT a screenshot and says why in the result (`none: <reason>`), the same stated degraded mode as `mini_app_publish`.
|
|
@@ -11,7 +11,7 @@
|
|
|
11
11
|
* screenshot, and only then the upload. The dashboard is the only validator; its refusal comes back verbatim with the step it refused.
|
|
12
12
|
*/
|
|
13
13
|
import path from "node:path";
|
|
14
|
-
import { archiveSource, assertNote, buildPlugin, uploadRevision, withScreenshot } from "@
|
|
14
|
+
import { archiveSource, assertNote, buildPlugin, uploadRevision, withScreenshot } from "@50arms/plugin-sdk/publish";
|
|
15
15
|
import { capturePluginRender } from "./plugin-screenshot.js";
|
|
16
16
|
/** The agent's authenticated dashboard client as the publish flow's transport. */
|
|
17
17
|
function clientTransport(client) {
|
|
@@ -75,7 +75,10 @@ export const GET_ROUTE_BOARD_SCOPE = [
|
|
|
75
75
|
["/api/team/quality/gates", "refuse"],
|
|
76
76
|
["/api/team/quality/people", "refuse"],
|
|
77
77
|
["/api/team/roles", "refuse"],
|
|
78
|
+
["/api/test-runs/backlog-snapshots/latest", "refuse"],
|
|
79
|
+
["/api/test-runs/culprits", "refuse"],
|
|
78
80
|
["/api/test-runs/file-times", "refuse"],
|
|
81
|
+
["/api/test-runs/slowest", "refuse"],
|
|
79
82
|
["/api/test-runs/stats", "refuse"],
|
|
80
83
|
["/api/usage/series", "refuse"],
|
|
81
84
|
["/api/users", "refuse"],
|
package/dist/tool-access.js
CHANGED
|
@@ -75,7 +75,7 @@ export const TOOL_ACCESS = {
|
|
|
75
75
|
// record names.
|
|
76
76
|
restart_notice: OPERATOR_SESSION_BOOTSTRAP,
|
|
77
77
|
// The one dispatch callback that stays a tool (DX-4525): it reads local files. Its dashboard route's own policy names the
|
|
78
|
-
// permission (
|
|
78
|
+
// permission (its route `policy`); every other callback is a `50arms_api` call to a route under `callback-routes.ts`.
|
|
79
79
|
"50arms_slack_reply": needsAndPostsTo("slack.threads.post", "slackReply"),
|
|
80
80
|
// DX-6847 / DX-6864 (DEC-571): its name before the rename, served beside the new one like the three API tools above; DX-6864 removes this entry.
|
|
81
81
|
danxbot_slack_reply: needsAndPostsTo("slack.threads.post", "slackReply"),
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@50arms/platform-mcp",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.440",
|
|
4
4
|
"description": "Stdio MCP server fronting the 50 Arms dashboard API for agents (operator sessions and dispatched workers alike): the generic 50arms_api/50arms_api_list/50arms_api_spec tools reach any route the caller's credential may call, plus dedicated agent-specific tools (plan_connect, request_permission, attach_file, and 50arms_slack_reply) (DX-3465, PLN-11 R-25).",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"type": "module",
|
|
@@ -36,8 +36,8 @@
|
|
|
36
36
|
"test:watch": "vitest"
|
|
37
37
|
},
|
|
38
38
|
"dependencies": {
|
|
39
|
-
"@
|
|
40
|
-
"@
|
|
39
|
+
"@50arms/docs": "0.1.73",
|
|
40
|
+
"@50arms/plugin-sdk": "0.2.51",
|
|
41
41
|
"@modelcontextprotocol/sdk": "1.29.0",
|
|
42
42
|
"@50arms/session-telemetry": "0.1.66",
|
|
43
43
|
"zod": "^3.25.76"
|