Skip to content

Repository files navigation

DevCompanion Extended

DevCompanion Extended is a local MCP server for developing Equicord plugins against the Discord runtime. It gives coding agents the missing half of plugin development: live webpack source, React ownership, Flux stores/actions, patch proof, reload control, and post-reload health checks.

The intended loop is: orient in the current Discord session, locate the runtime seam, prove the patch, edit the repository, reload, and verify the result.

Tools

Tool Use it for
discord Runtime orientation, platform/build context, enums, endpoints, and REST
component Visible UI location, React owner traces, props, DOM, and patch seams
module Landmark resolution, compact dossiers, source, exports, and dependency graphs
store / flux Store discovery, safe getters, action producers, handlers, and dependencies
intl Resolve Discord message hashes and stable #{intl::KEY} anchors
patch Rank targets, prove replacements, inspect plugin patch health, and verify live output
plugin Inspect plugin state/settings and intentionally change them
buildOutput / reloadDiscord Build diagnostics, renderer reloads, and readiness verification
interaction / trace / intercept Bounded runtime observation when static inspection is insufficient
batch / resource Combine safe reads and retrieve large evidence without bloating tool responses
evaluateCode Last-resort renderer evaluation when no dedicated tool answers the question

All 16 tools return structured MCP content as well as text for older clients.

Tooling

The server currently advertises 16 tools and 139 action-based subtools. Tool names stay stable; the action is passed through the tool's action argument unless the tool is a single operation.

buildOutput

Reads the development build log, captured renderer console, native-server readiness, and cached patch health.

Action What it does
status Return build-log metadata, native-server status, and renderer console-capture status without reading the full log.
recent Read a bounded window of the most recent build-output lines.
errors Return error-level build lines and captured renderer errors.
search Search build output with a literal query or regular expression.
runtimeReady Wait until the renderer and native DevCompanion boundary are ready for live calls.
reloadHealth Perform the authoritative post-reload check, including new build/console errors and cached patch-health totals.
clear Clear the captured build output; this mutates diagnostic state.

component

Locates visible Discord UI and bridges DOM elements to React fibers, owning webpack modules, CSS, stores, and patch seams.

Action What it does
inspect Inspect a selected element, its React component chain, CSS hints, and likely stores.
trace Trace an element through DOM, React ownership, module candidates, patch hints, Intl candidates, CSS, and stores; compact by default.
locate Rank visible UI candidates from selectors, text, component names, classes, bounds, or captured interaction targets.
find Find components through the component index or the same visible-element ranking pipeline used by locate.
rebuildIndex Clear and rebuild the cached component-name, Mana component, story, and UI-barrel indexes.
tree Return a bounded React render tree rooted at the selected element.
seam Rank viable patch boundaries; with replace, synthesize and prove up to three complete definitions without editing files.
clone Generate a pasteable React approximation of a visible element or active modal.
query Run a CSS selector and return bounded DOM matches; properties provides a strict attribute/property projection.
styles Read selected computed CSS properties or the properties that differ from a default element.
modify Temporarily change inline styles, classes, or attributes for live UI experiments; changes disappear on rerender.
text Read bounded text from an element and its immediate children.
path Build a DOM path and a shorter candidate selector for an element.
fiber Traverse summarized React fibers upward or downward from an element.
props Read React props and matching DOM properties; use properties to request only named values.
hooks Inspect the nearest function component's bounded hook list and supported hook values.
contexts Inspect React context providers above an element, including bounded keys and samples.
forceUpdate Force the nearest updatable class or function component to rerender.
state Read the nearest class state or function-component state-hook values.
owner Follow React debug-owner/parent relationships and summarize owning components.
root Identify the React root and summarize its root fiber for a selected element.
domTree Return a bounded DOM subtree with tags, IDs, classes, leaf text, and child truncation metadata.

module

Searches, resolves, inspects, and relates Discord webpack modules without requiring agents to guess minified identifiers.

Action What it does
search Search module factories by literal text, regular expression, or AND-style patterns.
find Use runtime finders such as props, code, display name, class name, export name, or pattern.
resolve Resolve a semantic landmark such as an Intl key/hash, CSS suffix, store, action type, enum-like symbol, or source literal to defining modules.
inspect Return a compact module dossier by default, or full source/runtime evidence on explicit request.
extract Read a bounded source range from one module factory.
exports Load and summarize a module's runtime exports; runtime values require explicit opt-in.
publicExports Statically recognize public export names from factory source without loading the module.
context Find a query inside a module and return bounded source context around each match.
diff Compare two module factories and report their source differences.
deps Return a module's direct webpack dependencies.
whereUsed Return modules that directly import the requested module.
path Find a bounded dependency path from one module to another.
neighborhood Return a bounded bidirectional dependency subgraph around a module.
functionAt Recover the enclosing function around a source offset or matching source landmark.
structure Summarize factory structure such as functions, strings, calls, exports, and source signals.
size Report source byte/character size for one module.
ids List known webpack module IDs in bounded pages.
patchedList List modules currently touched by registered plugin patches.
findFactory Inspect or search raw webpack factory functions without executing their exports.
stats Report webpack module, cache, analysis-index, and lazy-loader statistics.
loadLazy Invoke bounded lazy-module loaders and invalidate generation-bound analysis caches.
watch Start watching webpack module execution/loading for matching modules.
watchGet Read captures from an active module watch.
watchStop Stop and clean up a module watch.
suggest Rank patch anchors. strategy: "quick" preserves the fast legacy result; strategy: "exhaustive" adds semantic ownership, uniqueness proof, durability history, risks, and registered-factory coverage.
annotate Replace or label raw Intl hashes in module source with resolved message keys.
css Search/index Discord CSS-module class maps and their owning webpack modules.
components Search/index exported React components and component-like modules.

store

Discovers Flux stores, their public surface, subscriptions, and intentionally requested state.

Action What it does
find Search stores by name, methods, getters, or properties.
list List registered Flux store names, with optional filtering.
state Read a named property/getter or invoke a specifically requested store method.
call Invoke a named store method with explicit arguments.
subscriptions List Flux action types handled by a store.
methods Walk the store prototype chain and describe available methods/getters.
snapshot Read a bounded snapshot of all safe zero-argument getters.
guide Recommend likely safe getters and exact follow-up calls for a store task.
inspect Return store identity, module ownership, methods, subscriptions, and optional snapshot metadata.

flux

Maps Discord's Flux dispatcher statically and can perform bounded observation or explicit dispatch.

Action What it does
events List known dispatcher action types, optionally filtered.
types Alias the known Flux action-type inventory for type-oriented discovery.
dispatch Dispatch an explicit Flux action payload into Discord; this mutates renderer state.
listeners List stores, ordered handlers, and subscriptions for one event.
observe Capture a bounded synchronous window of matching Flux actions and summarize payload keys.
graph Show one store's dispatcher dependency node, dependencies, dependents, and handled actions.
producers Find source modules that produce a named action type.
chain Return the ordered store-handler execution chain for an action type.

intl

Turns Discord message hashes, keys, and text into readable, stable #{intl::KEY} patch anchors.

Action What it does
resolve Resolve a hash, key, or message query and return the best stable anchor.
search Rank Intl entries by message text, key, or hash.
scan Scan supplied text or a module factory for Intl hashes and resolve them in place.
discover Search runtime messages and source evidence for unknown hash-to-key mappings.
test Validate candidate keys against runtime hashes and add successful mappings to memory.
cache Report cache validation/collision statistics, clear the runtime cache, or flush the sorted validated map to disk through mode.

patch

Targets, validates, benchmarks, diagnoses, and live-verifies Equicord/Vencord patches against the current Discord bundle.

Action What it does
target Rank stable find anchors and candidate modules from source, Intl, CSS, component, or module evidence.
verify Validate find, match, and optional replace behavior without returning full previews.
preview Validate a patch and return bounded before/after replacement previews.
unique Check whether a prospective find string is unique and suggest stronger surrounding anchors when it is not.
analyze Audit registered plugin patches for missing, ambiguous, risky, or stale matches.
plugin Report one plugin's live patch health, module matches, optional replacement proof, and repo source mapping.
lint Lint patch definitions for brittle finders, regex hazards, syntax risks, and unsupported patterns.
finds Inventory and evaluate registered patch find values across plugins.
benchmark Benchmark one replacement regex against matching module source.
compare Compare two match/replacement strategies for correctness and performance.
slowscan Scan registered patches for slow or pathological match behavior.
conflicts Find modules patched by multiple plugins and summarize overlap severity.
diff Apply a proposed replacement in memory and return the resulting source difference.
broken Find broken runtime patches and classify why their find or replacement no longer matches.
prove Prove uniqueness, match, changed replacement, syntax, conflicts, and performance; adaptive by default, exhaustive on request.
source Map runtime evidence to plugin, patch, replacement, property, method, and exact line/column ranges when TypeScript is available.
verifyLive Produce a privacy-safe receipt from required DOM/store/Flux contracts; an allowlisted click runs only with executeTrigger: true.
repair Propose bounded, source-mapped repairs and promote only complete proof passes. Never edits files.

discord

Provides runtime orientation plus focused Discord platform, API, constants, design-system, and telemetry helpers.

Action What it does
context Return the current user, selected channel, and selected guild snapshot when that private runtime context is explicitly needed.
orient Return compact renderer readiness, module/store/plugin counts, build status, patch-health state, and recommended next calls.
api Make an explicit Discord REST request through RestAPI; non-GET methods mutate remote state and cannot be batched.
snowflake Decode a Discord snowflake into timestamp, age, worker, process, and increment fields.
endpoints List or search Discord endpoint constants and preview callable route builders.
common List or filter exports available from Equicord's @webpack/common surface.
enum Find runtime enum-like exports containing a named string or numeric member.
memory Report Chromium JavaScript heap usage and limits.
performance Report navigation/resource timing plus bounded DevCompanion per-action latency, size, cache, and resource-fallback telemetry.
gateway Inspect the active Discord gateway connection, heartbeat, sequence, and uptime state.
waitForIpc Poll until the current Discord user/runtime is available or the timeout expires.
constants Browse or filter Discord constant categories and bounded value samples.
experiments Summarize or search registered experiments, assignments, and override descriptors.
platform Report desktop/web platform flags and safe Discord environment/build endpoints.
tokens Browse Discord design tokens, semantic colors, themes, shadows, radii, and spacing.
icons List/filter available IconUtils helper functions for Discord asset URLs.
buildInfo Return Discord build number, version hash, release channel, platform, OS, and native build number.

plugin

Inspects and intentionally changes live Equicord/Vencord plugin state and settings.

Action What it does
list List plugins, enablement, authors, patch counts, and optional patch details.
enable Enable a plugin immediately when safe, or persist the state and report that a restart is required for patched plugins.
disable Disable a plugin immediately when safe, or persist the state and report that a restart is required for patched plugins.
toggle Switch a plugin between enabled and disabled using the same lifecycle/restart rules.
settings Read modern or legacy setting definitions, JSON-typed values, restart metadata, and redacted sensitive fields.
setSetting Persist one setting value and report its previous value plus restart requirement; sensitive values remain redacted.

evaluateCode

Action What it does
Single operation Execute JavaScript in the Discord renderer and serialize the final expression. This is a powerful mutation-capable escape hatch for questions no dedicated tool can answer.

trace

Provides longer-lived Flux action and store-change capture sessions than the bounded flux.observe helper.

Action What it does
events List currently known Flux events with optional filtering.
handlers List dispatcher handlers registered for one event.
storeEvents List action types handled by a named store.
start Start a bounded Flux trace with optional event/filter selection.
get Read events captured by the active trace without stopping it.
stop Stop the active Flux trace and return its final captures.
store Start watching selected state from a store and record changes caused by Flux activity.

intercept

Temporarily wraps a runtime exported function to capture calls and returns, including dotted export paths.

Action What it does
set Install a bounded interceptor on a module export/function path.
get Read captured arguments, return values, errors, and call counts from an active interceptor.
stop Restore the original function and return final interceptor results.

reloadDiscord

Action What it does
Single operation Reload the Discord renderer; the next DevCompanion request automatically waits for runtime readiness. Native-code changes still require a full application restart.

batch

Action What it does
run Execute multiple policy-classified read-only DevCompanion calls in one round trip. Unknown or mutating tool/action combinations are rejected before execution.

resource

Retrieves complete evidence that exceeded an action's inline response budget.

Action What it does
list List live resources with MIME type, stored/original UTF-8 bytes, truncation, access time, and expiry.
read Read a whole resource or an explicit UTF-8 byte range while updating its LRU access time.
clear Remove all stored resources.

interaction

Connects the next real UI interaction to its DOM target, React ownership, and associated Flux actions.

Action What it does
start Begin capturing the next click/interaction and related Flux activity.
get Read the current interaction target and captures without stopping the session.
stop Stop capture, clean up listeners/interceptors, and return final results.
once Start capture, wait for one interaction or timeout, then return and clean up in a single call.

Compact-first results

discord.orient, component.locate, component.seam, module.inspect, and patch.prove return decision-sized results by default. Pass detail: "full" when the compact result points to evidence you actually need. Explicit component.props, component.hooks, store.state, store.snapshot, module.exports, and evaluateCode remain the escape hatches for intentionally requested runtime values. Pass properties to component.props or component.query for a strict projection instead of serializing unrelated values.

Compatibility text is a concise summary; use structuredContent for the result object. Outputs that exceed their action-specific budget become a 1 KiB preview plus a resourceId, stored/original byte counts, expiry, truncation state, and exact resource.read arguments. discord.performance includes per-action DevCompanion p50/p95 latency, result sizes, cache hits, and resource fallbacks for the current renderer session, with its renderer-only timing scope reported explicitly.

Anchor intelligence and repair

Use module.suggest with strategy: "exhaustive" when a patch needs a durable anchor rather than a fast shortlist. The scanner derives candidates from validated Intl keys, stores, Flux action types, public exports, stable methods/properties, enum members, CSS source keys, and meaningful literals. It rejects minified names, module/chunk IDs, rendered hashes, assets, URLs, build numbers, import noise, and locale-definition bundles. Unique semantic anchors win; bounded two-anchor expressions are considered only when a strong single anchor is not unique.

Ranking is proof-ordered: correct target uniqueness, cross-build survival, verified functional success, semantic strength, risk count, then compactness. Compact results contain the best five candidates and stay within 3 KiB. Full evidence is resource-backed when necessary. Scans cover registered factories without silently loading lazy chunks; coverage and the explicit module.loadLazy follow-up keep incomplete runtime coverage from becoming a success verdict.

Durability history is enabled by default at Discord's userData/devcompanionExtended/anchor-history.json. Version 2 migrates version 1 records and adds bounded proof, repair, functional-pass, and deterministic-failure counters. It still stores only SHA-256 anchor/fingerprint digests, build hashes, kinds, outcomes, and timestamps—never selectors, source, runtime values, messages, or UI data. The atomically replaced file remains bounded to eight builds, 4,096 records, and 1 MiB.

Use patch.repair with pluginName plus patchIndex, or with an explicit find, match, and replace. It recovers likely targets from surviving match/semantic evidence, generates bounded candidates, and runs every proposal through the complete patch.prove pipeline. It never edits repository files and never labels an unproved candidate verified. patch.plugin separately reports APPLIED, NOT_APPLIED, CONSUMED_NO_CHANGE, FIND_AMBIGUOUS, or FIND_NO_MATCH; registration is not functional proof. After applying a proposed definition, reload, require buildOutput.reloadHealth, inspect patch.plugin, and finish with selector-backed patch.verifyLive.

patch.prove and patch.repair use benchmarkMode: "adaptive" by default: static failures skip timing, while valid replacements get a cold shot, bounded warmup, calibrated samples, and confirmation rounds inside a 40 ms budget. An unmeasurable valid replacement is BENCHMARK_INCONCLUSIVE, never PASS. Use benchmarkMode: "exhaustive", or explicit iterations/rounds, for the compatible 10,000-iteration, three-round path. patch.benchmark remains exhaustive.

For a visible seam, pass the exact replacement template to component.seam as replace; optional pluginName adds conflict and repository context. DCE returns only definitions that pass the canonical proof pipeline. Use patch.source with patchIndex and replacementIndex for exact TypeScript-AST property ranges. Computed/function values are marked unsupported and lexical fallback is precision: "coarse"; runtime-only modules return unmappedRuntimeModule instead of a guessed file.

patch.verifyLive accepts up to eight typed checks: DOM present/absent/attributeEquals, store getter-style truthy/falsy/equals/changed/unchanged, and Flux minimum counts. All checks are required unless required: false. testSelector remains a compatibility shorthand for one required DOM-present check; testTrigger is only a hint. A declarative click executes only when executeTrigger: true, which makes the call a write and therefore non-batchable. Receipts expose counts, types, digests/comparisons, timing, and verdicts—never DOM text, store values, Flux payloads, IDs, or message data. Only VERIFIED receipts teach functional anchor success.

Prior art: Sadan's scored unique-find concept helped motivate this problem space. DevCompanion Extended's semantic scanner, proof ordering, bounded durability history, and repair pipeline are an independent implementation and do not reuse AGPL source.

Typical workflows

Visible UI

  1. Call discord.orient.
  2. Locate visible text or a component with compact component.locate; request full detail only when its selector/owner summary is insufficient.
  3. Follow ownership with component.trace, then ask component.seam for viable insertion points.
  4. When the intended replacement is known, pass it to component.seam to synthesize and prove definitions; otherwise use module.suggest or patch.target.
  5. Apply only a complete proof pass.

Store and Flux behavior

  1. Resolve a store landmark with module.resolve, then read its compact module.inspect dossier.
  2. Use store.guide before guessing getter names.
  3. Trace producers and ordered handlers with flux.producers, flux.chain, or flux.graph.
  4. Use interaction.once only when the next click is the clearest way to identify the action.

Patch and reload

  1. Prove the replacement with adaptive compact patch.prove; use exhaustive mode or detail: "full" only when needed.
  2. Edit and build the plugin.
  3. Call reloadDiscord for renderer-only changes.
  4. Require buildOutput.reloadHealth to report ready.
  5. Require patch.plugin registration evidence, then finish with typed patch.verifyLive checks. Execute a click only with explicit opt-in. A successful build or registration alone is not functional proof.

Install

Install the folder as an Equicord/Vencord user plugin, rebuild, then enable devcompanionExtended in Discord. The default MCP endpoint is http://127.0.0.1:8487; the ipcPort plugin setting changes it and requires a full Discord restart.

Codex

For one trusted repository, add this to <project>/.codex/config.toml. For every trusted Codex project, put the same block in ~/.codex/config.toml instead.

[mcp_servers.devcompanion]
url = "http://127.0.0.1:PORT"

Start a fresh Codex task after changing MCP configuration. Make sure not to forget to make the PORT the same as your ipcPort setting config!

Other MCP clients

Configure a Streamable HTTP server named devcompanion at http://127.0.0.1:8487 according to your agent's docs.

Equicord agent skill

The distributable skill is in skills/equicord-plugin-dev. Copy that directory into your agent's skill directory, then invoke $equicord-plugin-dev for Equicord plugin tasks. The package includes progressive references for patches, UI, Flux, stores, settings, commands, menus, hooks, and TypeScript patterns, plus MCP dependency metadata for DevCompanion.

Batching and resources

batch accepts read-only calls only. Dispatches, REST writes, reloads, settings changes, plugin toggles, watches, and other mutations are rejected. Unknown tools/actions are also rejected instead of being assumed safe.

Oversized results become short previews with a resourceId. Read them with resource.read. Resources expire after ten minutes and are bounded by count, per-entry bytes, and aggregate bytes; truncation and original-byte metadata are explicit.

About

No description, website, or topics provided.

Resources

Stars

4 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages