Skip to content

MCP

MCP Server Reference ​

Every key accepted in an mcpServers entry. See MCP Integration for concepts and workflow.

File shape ​

json
{
  "mcpServers": {
    "<server-name>": { }
  }
}

The server name becomes part of every tool's namespaced name (mcp__<server-name>__<tool>), so keep it short and stable. Renaming a server renames every tool it provides, which the model sees as a different tool set.

Transport selection ​

ConditionTransport
command is setstdio
type is "http" or "streamable-http"Streamable HTTP
url is set and command is notStreamable HTTP

All keys ​

KeyTypeDefaultApplies toPurpose
typestringinferredboth"http" or "streamable-http" to force HTTP. Usually unnecessary
commandstring—stdioThe executable to run
argsstring[][]stdioArguments passed to command
envobject{}stdioEnvironment variables for the subprocess
urlstring—HTTPThe server endpoint
headersobject{}HTTPStatic request headers. Values support ${VAR} expansion
oauthobject—HTTPEnables the OAuth 2.1 flow. See below
toolsstring[]allbothAllowlist of tool names to register
readOnlybooleanfalsebothTreat every tool from this server as safe-tier
timeoutMsnumber30000bothPer-request timeout. 0 uses the default
requiredbooleanfalsebothFail startup if this server does not connect

stdio servers ​

json
{
  "mcpServers": {
    "filesystem": {
      "command": "npx",
      "args": ["-y", "@modelcontextprotocol/server-filesystem", "/workspace"],
      "env": { "LOG_LEVEL": "warn" }
    }
  }
}

The subprocess is started at agent startup and shut down when the agent exits. It inherits nothing from your environment except what you list in env.

HTTP servers ​

json
{
  "mcpServers": {
    "historian": {
      "type": "http",
      "url": "https://historian.internal/mcp",
      "headers": {
        "Authorization": "Bearer ${HISTORIAN_TOKEN}",
        "X-Site": "plant-3"
      },
      "timeoutMs": 120000
    }
  }
}

Environment expansion ​

${VAR} in a header value expands from the environment. An unset variable expands to empty with a warning. A missing token should produce a 401 you can read, not a startup crash that hides which header was wrong.

OAuth ​

json
{
  "mcpServers": {
    "tickets": {
      "url": "https://tickets.example.com/mcp",
      "oauth": {
        "scopes": "tickets.read tickets.write"
      }
    }
  }
}
KeyTypePurpose
scopesstringSpace-separated scopes to request
client_idstringA pre-registered client id. Omit to use dynamic registration (RFC 7591)
client_secretstringOnly for a confidential client. Omit for the public-client flow

An empty "oauth": {} object is valid and enables the flow with discovery-supplied defaults.

Standards implemented ​

RFC / specRole
OAuth 2.1Authorisation-code flow, public client
PKCE (S256)Mandatory. plain is not accepted
RFC 9728Protected Resource Metadata discovery
RFC 8414Authorization Server Metadata discovery
RFC 8707Resource indicator, binding the token to that server
RFC 7591Dynamic client registration, when no client_id is given

Not implemented: the CIMD registration variant, device-code flow, token introspection. None is needed for the standard remote-server flow.

Token storage ​

Path~/.config/oasis-agent/mcp-tokens.json
OverrideOASIS_MCP_TOKEN_STORE, or XDG_CONFIG_HOME
RefreshAutomatic, one minute before actual expiry

Run the browser flow once:

bash
oasis-agent --mcp-config <path> --mcp-login

It authenticates every configured HTTP server, reports, and exits. It never runs a turn.

Curation ​

tools: the allowlist ​

json
{ "tools": ["query_series", "list_tags"] }

Only the named tools are registered. Everything else the server offers is ignored. This is the primary lever: a server that exposes forty tools costs forty tool schemas in your prompt prefix, and the model has to read all of them on every turn.

readOnly ​

json
{ "readOnly": true }

Every tool from the server is treated as safe-tier and never prompts.

This is a claim you are making about the server

The agent has no way to verify it. Set it only on a server you know cannot change anything.

Without readOnly, MCP tools are treated as mutating and prompt according to the permission mode.

required ​

json
{ "required": true }
A server that fails to connect
false (default)Skipped, with a message. The run continues
trueStartup fails

Use true when the run is meaningless without that server's tools, and to protect the prompt cache from a flaky server silently reshaping the schema.

Startup output ​

Each server reports as it loads:

EventMeaning
Server startingConnection attempt begun
Server readyConnected. Reports tool count and read-only status
Server errorFailed to connect. Skipped unless required
Tool renamedA namespaced name collided and was disambiguated with a hash suffix

A tool renamed message is worth reading. The model will see the renamed tool, not the obvious one, and a collision usually means two config entries that wanted to be the same server.

Tool naming rules ​

text
mcp__<sanitised-server>__<sanitised-tool>
RuleBehaviour
Maximum length64 characters, truncated if longer
SanitisationCharacters outside the allowed set are replaced, so "my server" and "my:server" can collide
CollisionResolved with a short hash suffix and reported at startup

Complete example ​

json
{
  "mcpServers": {
    "filesystem": {
      "command": "npx",
      "args": ["-y", "@modelcontextprotocol/server-filesystem", "/workspace"]
    },
    "historian": {
      "type": "http",
      "url": "https://historian.internal/mcp",
      "headers": { "Authorization": "Bearer ${HISTORIAN_TOKEN}" },
      "tools": ["query_series", "list_tags"],
      "readOnly": true,
      "timeoutMs": 120000,
      "required": true
    },
    "tickets": {
      "url": "https://tickets.example.com/mcp",
      "oauth": { "scopes": "tickets.read tickets.write" },
      "tools": ["create_ticket", "search_tickets"]
    }
  }
}

software-defined automation