Skip to content
AI

AI Agent Access (MCP Server)

The MCP server lets an external AI client such as Claude Code, Codex, or any other Model Context Protocol host, connect to a running AmiCore instance and operate it through tools. The client discovers the available 3forge Enterprise operations, then calls them by name to inspect and drive the deployment.

The server is an Enterprise plugin that runs inside the component and exposes an authenticated HTTP endpoint on Enterprise's REST surface (the Web port by default) or REST's own socket if the deployment moves it (see Enabling and configuring).

What Gets Exposed

Enterprise's console operations become MCP tools. Every component (Center, Web, Relay) and cross-component utility (logs, documentation) registers its operations at startup, so a single connection can reach all of them.

Tools are named by their owner so one client can talk to the whole deployment:

{componentType}_{name}     e.g.  center_execute, web_console, relay_addFeedhandler
{frameKey}_{name}          e.g.  log_search, aidoc_get_documentation

The component prefixes are center_, web_, and relay_; cross-component utilities use their frame key (log_, ami_, aidoc_, …).

Grouped Operations and the op Selector

Most operations are grouped: rather than one tool per operation, related operations share a tool and are selected with a required op parameter. Reading a panel list and deleting a panel are both Web operations, but they live in different tools because they carry different risk:

Tool Selected with Holds
web_console op=panels, op=sessions, op=tableColumns, … Read-only introspection
web_execute op=importWindow, op=updatePanel, … Layout and datamodel mutation
web_danger op=deletePanel, op=killSession, … Destructive operations
web_verify op=panelJson, op=datamodel, op=script Validation before applying

Each tool's schema lists its valid op values and the parameters each one takes, so a client discovers them the same way it discovers any tool. A call with a missing or unknown op is rejected with the valid list.

Not every operation is grouped. Some remain standalone tools, such as relay_addFeedhandler and web_script.

Note

When a deployment runs more than one component of the same type (e.g: 2 Centers), tools accept an optional componentId parameter to choose which instance to target. With a single instance of a type, it can be omitted.

Enabling and Configuring

The MCP server is a REST plugin with the id MCP, served by the Enterprise REST server at /3forge_rest/mcp. Where that path is served is decided by ami.rest.uses.web.port, which ships as web, so on a default install the endpoint is on the Web component's ports: https://<host>:33333/3forge_rest/mcp.

REST plugins are loaded via the ami.rest.plugin.classes property. By default, it includes every discovered plugin except the canonical query/admin endpoints:

ami.rest.plugin.classes=*,!QUERY,!ADMIN

Because MCP is matched by the *, it is enabled by default . To disable it, add !MCP to the list in local.properties:

ami.rest.plugin.classes=*,!QUERY,!ADMIN,!MCP
Property Default Purpose
ami.rest.plugin.classes *,!QUERY,!ADMIN Which REST plugins load; !MCP disables this endpoint
ami.rest.uses.web.port web Which Web component's port serves REST. false moves REST to its own socket instead (below)
ami.mcp.tools.disabled (empty) Comma-separated blacklist of tool names; supports prefix_* wildcards

Moving REST off the Web port

ami.rest.uses.web.port decides where the whole REST surface, /3forge_rest/mcp included, is served. It uses the named Web component's own http.port / https.port values by default.

To bind REST to its own socket instead, set it to false and provide an alternative free port:

ami.rest.uses.web.port = false
ami.rest.http.port     = 8766     # example port, plain HTTP, no certificate to trust

Note

ami.rest.http.port has no shipped default, so the REST socket only exists once you choose a port for it. 8766 above is an example, not a default.

On a trusted, closed network, a dedicated plain-HTTP REST port lets MCP clients connect without any TLS setup, while the Web port keeps serving the browser over HTTPS. Do not use it on an untrusted network: Basic credentials and every response travel in clear text. It is one or the other, not both. Moving REST off the Web port means https://<host>:<https.port>/3forge_rest/* stops answering, and any other client of the REST surface has to be re-pointed too.

The tool catalog is built lazily on the first request, so every component has finished registering before any tool is resolved.

Restricting the Tool Set

To hide operations you do not want an agent to reach, for example all Relay mutators, list them in ami.mcp.tools.disabled:

1
2
3
ami.mcp.tools.disabled=relay_addFeedhandler,web_danger
# or a whole family with a wildcard:
ami.mcp.tools.disabled=relay_*

Matching is on the tool name, and a disabled tool is dropped at registration so it never appears in tools/list.

Warning

This property cannot disable a single op. Naming a grouped tool disables every operation in it, and naming an operation such as web_killSession matches nothing at all, because the tool is web_danger and killSession is one of its op values. To take away one operation of a group and keep the rest, use an agent allowlist instead: see Agents and their tool allowlists.

Authentication

The MCP tools are high-privilege (SQL execution, component management, layout deployment), so every request is authenticated by the REST server before the plugin runs. 2 schemes are accepted, tried in this order:

  1. Web session. If the request carries an active Web session, the session cookie set when a user logs into the Web component in the browser, the request runs as that logged-in user. No credentials are sent on the request itself; it rides on the existing browser login. This is the path taken when the endpoint is called from within an authenticated Web session on the same host.
  2. HTTP Basic. Otherwise, the caller supplies an Authorization: Basic <base64(user:pass)> header. The username and password are verified against the Web REST authenticator (auth namespace amiweb_rest), the same user store as Web login. This is the scheme an external MCP client (Claude Code, Codex) uses, since it has no browser session.

The header value is the base64 encoding of username:password:

1
2
3
username:password  =  <user>:<password>
base64             =  <base64 of that string>
header             =  Authorization: Basic <base64 of that string>

The request outcome depends on the result:

Result HTTP status
Authenticated (session or valid credentials) request proceeds
Missing Authorization header and no web session 401 (with WWW-Authenticate: Basic)
Invalid username or password 401
Account locked, service disabled, or user-count exceeded 403

The resolved user is the identity every tool call runs as, so a caller only reaches operations their entitlements permit.

Connecting a Client

Point an MCP server entry at the endpoint on the web port, and supply credentials. For Claude Code / Codex:

1
2
3
4
5
6
7
8
9
{
  "mcpServers": {
    "ami-runtime": {
      "type": "http",
      "url": "https://<host>:<webHttpsPort>/3forge_rest/mcp",
      "headers": { "Authorization": "Basic <base64(user:pass)>" }
    }
  }
}
  • type must be http, because the endpoint is a plain HTTP JSON-RPC transport (below), not the SSE or stdio transports some clients default to. Omitting it is the most common "it will not connect" cause.
  • url is the REST endpoint on the web port: the http.port for plain HTTP, or the https.port for TLS.
  • headers.Authorization carries the Basic credentials.

Over HTTPS with the default self-signed certificate you must also configure the client to trust it. See Transport security below; a config with only type / url / headers connects over plain HTTP but is rejected over TLS until trust is set up.

Transport is plain request/response: the client POSTs a JSON-RPC 2.0 request and reads the JSON-RPC response. A GET is declined with 405 (there is no server-initiated event stream).

The Authorization value is reversible Base64, not a secret

Basic <base64(user:pass)> is a trivially decodable encoding, not encryption. Anyone who reads the header recovers the password. Send it only over a trusted transport (TLS, or a closed network), and never commit a config file carrying production credentials; use a placeholder and inject the real header at deploy time.

Once connected, the client lists the Enterprise tools and can call them by name (center_execute, web_console with an op, and so on). The server's handshake includes an instructions string pointing the agent at the built-in reference. The agent can call get_documentation("admin") for the full tool reference, or get_documentation() with no argument to list all reference topics.

Transport Security and Self-Signed Certificates

The endpoint is served on the Web listeners. The web component can serve plain HTTP, HTTPS, or both, configured in its local.properties:

1
2
3
4
5
6
http.port=33332

# HTTPS: supply a keystore for the certificate:
https.port=33333
https.keystore.file=keys/3forge.pem
https.keystore.password=${ami.keypass}
Property Purpose
http.port Plain-HTTP listener port
https.port HTTPS listener port
https.keystore.file Keystore (Java keytool format) holding the server certificate and private key
https.keystore.password Password for that keystore

Set the keystore password for your deployment

The shipped defaults.properties sets https.keystore.password=${ami.keypass}, so the effective keystore password is whatever ami.keypass resolves to. Override ami.keypass, or https.keystore.password directly, before the instance is reachable by anyone else. See Security Defaults.

Self-signed certificate: 2 things must hold

Enterprise ships a self-signed certificate in the default keystore. Over HTTPS a validating MCP client, as most are, needs both of the following, or it refuses to connect:

  1. The client must trust the certificate. It is self-signed, so no CA vouches for it, and the client has to be told to trust it explicitly.
  2. The certificate's name must match the URL host. If the certificate carries no Subject Alternative Name matching the host you connect to, the client rejects it with ERR_TLS_CERT_ALTNAME_INVALID (hostname mismatch) even after it is trusted. The HTTPS listener still starts normally, and the failure is entirely client-side. Trusting alone is not enough. Contact 3forge support for the specifics of the certificate shipped with your build.

3 ways to satisfy both requirements:

  • Move REST onto its own plain-HTTP port, by setting ami.rest.uses.web.port=false and choosing an ami.rest.http.port as described above, then connecting to http://<host>:<amiRestHttpPort>/3forge_rest/mcp. This sidesteps certificate validation entirely, so confine it to a trusted, closed network: Basic credentials and every response travel in clear text. The Web HTTP port is not an option here: with TLS enabled by default it redirects to the HTTPS port.
  • Regenerate the keystore with a SAN that matches your host. For example, to reissue a cert valid for localhost / 127.0.0.1 (add your real deployment hostname to the SAN list as needed):

    1
    2
    3
    keytool -genkeypair -alias 3forge -keyalg RSA -keysize 2048 \
      -dname "CN=localhost" -ext "SAN=dns:localhost,ip:127.0.0.1" \
      -validity 1000 -keystore keys/3forge.pem -storepass <ami.keypass>
    
  • Install a CA-signed certificate (recommended for production): point https.keystore.file / https.keystore.password at a keystore whose certificate is issued by a trusted CA for your real hostname. Both requirements are then met by the CA chain and the cert's SAN.

Replacing the server certificate is a server-side task shared by every client, not just MCP. See Server Certificates for the full procedure.

Trusting the Certificate in the Client

A client trusts the public certificate, not the keystore (the keystore holds the private key, so never distribute it). Export the certificate to a PEM first, because Enterprise does not ship one:

keytool -exportcert -rfc -alias 3forge -keystore keys/3forge.pem \
  -storepass <ami.keypass> -file 3forge-cert.pem

For a Node-based MCP client (many editor-hosted clients are Node), point NODE_EXTRA_CA_CERTS at that exported PEM so Node adds it to its trust store:

export NODE_EXTRA_CA_CERTS=/path/to/3forge-cert.pem

A JVM-based client instead imports it into a truststore (keytool -importcert) referenced by -Djavax.net.ssl.trustStore. Either way requirement 2 still applies: the exported certificate must carry a SAN matching the host in the client's url, or trust succeeds but the hostname check still fails.

Verifying It Is Running

On startup the plugin logs a line confirming the endpoint is live:

AMI MCP: serving authenticated MCP at /3forge_rest/mcp (via AmiRestServer on the web port)

A connecting client confirms the endpoint by completing the MCP initialize handshake and listing tools.

Results and Errors

Tool results are serialized to JSON: tables come back as row arrays, scalars and maps as their natural JSON. A failed tool returns an error object rather than a transport fault, so the calling agent can read the message and adapt:

{"ok": false, "error": "No such table: FOO"}

Warning

The MCP server grants an authenticated external process the ability to operate your Enterprise instance. Bind the web port to a trusted network, restrict the exposed tool set with ami.mcp.tools.disabled, and connect with an identity whose entitlements match what the agent should be allowed to do.

  • 3forge MCP Plugin for AI Coding Tools: a ready-made client plugin (Claude Code, Codex, Copilot) that connects to this server with 3forge skills, agents, and commands.
  • Mandatory Mutual TLS: the client-certificate allowlist enforced on the Center, JDBC, Relay, and Gateway listeners. It does not apply to the Web listener that serves this endpoint, which authenticates with HTTP Basic instead.
  • Ask AI Chatbot -> agents and tool allowlists: narrowing what a single agent may call, beyond the server-wide ami.mcp.tools.disabled.