Skip to main content
Glama

cms-mcp

An MCP (Model Context Protocol) server that reproduces the CMS calls made by the CoreNeo Eclipse plugin's New Query / Service / Exception / Screen / ESB actions — generating OIDs / exception ids and checking definition-name availability — implemented purely in Node.js.

It talks to the CMS the same way the plugin's CmsHttpClient does: Spring HttpInvoker over HTTP with HTTP Basic auth. Because HttpInvoker uses Java's native binary serialization, this project ships a small, focused implementation of the Java Object Serialization Stream Protocol (src/java-serialization.js).

Tools

Tool

CMS method

Notes

generate_oid

generateOid(String platform)

Returns the OID as a string (Java long). Used by Query/Service/Screen/ESB.

get_next_exception_id

getNextExceptionId()

Used by the New Exception action.

generate_screen_name

generateComponentScreenName(CmsNeoComponent)

New FBML/XAML Screen wizard. Returns <module><number> (e.g. ANALYTICS20001). Side-effecting: increments the module screen counter.

list_components

getComponentList()

Lists components; needed to pick a component for name checks / screen names.

check_definition_name

existsQueryDefinition / existsServiceDefinition / existsRegionDefinition / existsPopupDefinition / existsDadDefinition

The wizard's "Check Name" button. Supports query/service/region/popup and esb.

How check_definition_name works (capture-replay)

The existsXxxDefinition methods take a CmsNeoComponent object argument. Instead of hand-modelling that entity's serialized form (fragile: field order + every serialVersionUID), the client first calls getComponentList(), captures the real serialized component objects the server sends, and replays the chosen one as the argument — reusing the server's own class descriptor. So name checks stay correct even if the entity changes shape, as long as getComponentList works.

ESB name checks

type: "esb" maps to existsDadDefinition(component, name, GLOBAL_SCOPE, code) — the same call NewESBConfigurationPage makes. Pass configType (Map/GroovyWsdl/GroovyRest/Xslt/Uddi); its code (1–5) becomes the definition type. Notes matching the plugin:

  • Uddi has no uniqueness check → always reports exists:false with checkedOnServer:false (no server call).

  • ESB scope is always GLOBAL_SCOPE (name unique across all components).

  • ESB names are not normalized (kept as-is), and the stored name includes the file extension — e.g. check EXT_SWIFT.cfg, not EXT_SWIFT.

Related MCP server: Vulnerable MCP Server

Configuration

By default the server reads the same files the Eclipse plugin uses — no env vars needed:

File

Values read

~/.symphony/cms_eclipse_config.xml

serviceUrl (the HttpUserService HttpInvoker bean)

~/.symphony/cms_eclipse.properties

cmsUserName, cmsPassword (AES-decrypted), cmsDBEnvironment (default platform)

cmsPassword is AES-128/ECB/PKCS5 encrypted with the fixed key from AESConverter — the server decrypts it in memory exactly like the plugin does.

Overrides (all optional)

Environment variables override the files when set:

Var

Meaning

CMS_URL

Full remoting URL.

CMS_HOST / CMS_PORT / CMS_CONTEXT

Build a URL when no CMS_URL/xml URL. Defaults 8081 / cms_server.

CMS_USERNAME / CMS_PASSWORD

Plain (already-decrypted) credentials.

CMS_PLATFORM

Default platform for generate_oid (else cmsDBEnvironment, else DEV).

CMS_TIMEOUT_MS

Per-call timeout (default 60000).

SYMPHONY_DIR

.symphony directory (default ~/.symphony).

CMS_CONFIG_XML / CMS_PROPERTIES

Point at specific config files (e.g. cms_eclipse_config_kaspi.xml).

On startup the server logs (to stderr) the resolved target, user, platform, and which file each value came from.

Register in Claude Code

Nothing extra needed — it picks up ~/.symphony automatically:

claude mcp add cms -- node C:/workspaces/cms/cms-mcp/src/index.js

To target a different environment file:

claude mcp add cms --env CMS_CONFIG_XML=C:/Users/you/.symphony/cms_eclipse_config_kaspi.xml \
  -- node C:/workspaces/cms/cms-mcp/src/index.js

Or in your MCP client config (.mcp.json / client settings):

{
  "mcpServers": {
    "cms": {
      "command": "node",
      "args": ["C:/workspaces/cms/cms-mcp/src/index.js"]
    }
  }
}

Run / test

npm test          # offline unit + wire + MCP-handshake tests (no live CMS needed)
npm start         # start the stdio server (reads ~/.symphony by default)

Test against the live CMS

scripts/live-check.mjs exercises the real calls directly (reads ~/.symphony, no MCP client needed):

node scripts/live-check.mjs                                  # generate_oid + list_components
node scripts/live-check.mjs oid                              # generate_oid
node scripts/live-check.mjs exid                             # get_next_exception_id
node scripts/live-check.mjs screenname "<component>"         # generate_screen_name
node scripts/live-check.mjs components                       # list_components
node scripts/live-check.mjs check query "<component>" "<NAME>"   # check_definition_name
node scripts/live-check.mjs esbcheck Map "<component>" "<NAME.cfg>"  # ESB name check

Debugging aids: scripts/dump-response.mjs <method> writes a raw serialized response to tmp/<method>.bin; scripts/parse-bin.mjs <file> parses it and reports where (if anywhere) deserialization derails.

Status

Verified end-to-end against the live CMS: generate_oid, get_next_exception_id, list_components (720 components), and check_definition_name for query/service/region/popup and esb (correct true/false both ways). The full getComponentList response also re-serializes byte-for-byte identically, which proves the codec is faithful to the JVM for the real CmsNeoComponent graph.

Notes / gotchas

  • Component descriptors are captured from getComponentList, not constructed, so they can't drift. Constructed descriptors that must stay correct live in src/http-invoker.js (RemoteInvocation) and src/java-serialization.js (java.lang.String, and the enum descriptors).

  • Enum gotcha (already handled): the java.lang.Enum super descriptor must be flagged SC_ENUM too (0x12), else the server throws InvalidClassException: cannot bind non-enum descriptor to an enum class.

  • Field-type signature strings in a class descriptor may be back-references, so the reader resolves them via readContent (not a fresh string read).

Layout

src/
  java-serialization.js  JOSP reader + writer (handles, classdesc, enum, array, block-data)
  http-invoker.js        RemoteInvocation build + POST (Basic auth) + RemoteInvocationResult parse
  values.js              node -> JS conversions; entity field / collection extraction
  cms-client.js          generateOid, getNextExceptionId, getComponentList, existsDefinition
  symphony-config.js         reads ~/.symphony config xml + properties; AES password decrypt
  index.js               MCP server + tool definitions
test/                    serialization / wire / mcp-handshake tests

Resources

Unclaimed servers have limited discoverability.

Looking for Admin?

If you are the server author, to access and configure the admin panel.

Related MCP Connectors

Related MCP Servers

  • F
    license
    Not graded
    quality
    D
    maintenance
    A simple demonstration MCP server that provides an echo tool and resource for learning how to build MCP servers. Serves as a starting point and template for creating custom MCP server implementations.
    1
    -
  • F
    license
    Not graded
    quality
    B
    maintenance
    A simple HTTP-based MCP server that provides demo tools (get_test_string, echo, check_maintenance), greeting prompts, and test resources, with optional OAuth 2.1 support.
    -