Skip to Content

MCP Server

Any Golem application can be automatically exposed through MCP (Model Context Protocol). It requires no code — MCP is available for any agent automatically — but it must be enabled in the application manifest.

The MCP server uses port 9007 by default, separate from the HTTP API gateway on port 9006.

Enabling MCP

Add an mcp section to golem.yaml choosing which agents to deploy to which subdomains per environment:

mcp: deployments: local: - subdomain: mcp-demo # resolves to mcp-demo.localhost:9007 by default agents: CounterAgent: {}

After golem deploy, the MCP server is available at http://mcp-demo.localhost:9007/mcp using the streamable HTTP protocol.

Exporting native tools

Native Golem tools can be exported without deploying an agent. A complete tools-only application declares the implementation, binds it to an owner component, and selects commands for the MCP deployment:

app: mcp-tools-demo environments: local: server: local components: my-app:file-tools: componentWasm: build/file-tools.wasm my-app:tool-owner: componentWasm: build/tool-owner.wasm tools: file-tools: {} tools: file-tools: component: my-app:file-tools mcp: deployments: local: - subdomain: mcp-demo tools: file-tools: ownerComponent: my-app:tool-owner include: - read-file - list **

The top-level declaration provisions the file-tools implementation. The components.my-app:tool-owner.tools binding authorizes each fresh owner to invoke it; an agent-only binding is insufficient. Component bindings also become defaults for real agents exported by that component, where agent bindings and presets can narrow or remove them. Use a separate component with no agents as the owner when those defaults are not wanted. The implementation component and owner component may be different, as above.

Finally, mcp.deployments.local[].tools.file-tools exports the selected executable commands. The deployment must contain at least one agent or tool. All security scheme references in it must agree; that scheme protects the whole domain.

For a remote release, put its exact release reference in the top-level declaration instead of component. The target environment must have a grant for that release. An application deployment plans and automatically reconciles grants derived from its remote declarations when the deploy actor has permission; separately managed grants are not removed.

Each call creates a fresh ephemeral owner using that component’s configuration, permissions, files, and tool bindings. It instantiates the deployed component, including its core initializers, but does not select an agent type or call an agent constructor. Tool and middleware bodies run through native invocation queueing and permission checks. Accepted execution is not restarted after owner loss, including interruption during core initialization. To invoke a tool on an existing real agent, use the native REST API or golem tool invoke --agent, not MCP.

Commands and schemas

Only commands with bodies become MCP tools; a parent with its own body is exported alongside its executable descendants. Names are lowercase, hyphens become underscores, and path segments are joined with underscores: file-tools read-file becomes file_tools_read_file. Aliases produce additional tools that invoke the same canonical command. Name collisions fail deployment.

Use either include or exclude, never both. Patterns are space-separated command paths without the tool prefix: * matches one segment and ** matches any depth. Selecting a canonical command includes its aliases; excluding it also removes its aliases.

Inputs use the human-readable JSON shapes advertised by tools/list, including defaults and repeated collections. Constraints are enforced before invocation and by native tool dispatch. Host-managed capabilities and nested typed streams cannot be exported. Standard annotations become readOnlyHint, destructiveHint, idempotentHint, and openWorldHint; these hints do not change permissions or execution semantics.

Finite stdin, stdout, and stderr

MCP buffers each byte stream, with a separate 16 MiB limit for stdin, stdout, and stderr. Exceeding any limit fails the MCP call; Golem does not truncate stream data. Declared stdin becomes an _stdin string argument, required only when the tool requires stdin. It contains UTF-8 text when every declared MIME type is textual, or base64 otherwise. Stdout and stderr are drained concurrently while stdin is being sent. Each becomes text, image, audio, or an embedded resource according to its declared MIME type. An output declared only with text/* MIME types must contain valid UTF-8 or the MCP call fails.

MCP has no native fd 2, so successful content lists stdout before stderr and tags every projected block with _meta["golem.cloud/tool-channel"] set to "stdout" or "stderr". Binary resources use distinct /stdout and /stderr URIs. This order does not imply cross-channel byte ordering, and stderr content alone does not set isError. On tool failure Golem still drains both outputs but omits their content, matching the existing stdout limitation.

Structured results are returned as structuredContent matching the advertised output schema, with a value wrapper when needed to produce a root object.

Invalid parameters, constraint violations, and invalid results produce JSON-RPC -32602 errors. Tool execution and custom errors produce isError: true. MCP does not expose native formatter selection, exit-code semantics, repetition modes, the alias graph, or middleware composition; middleware still runs normally.

Listings and calls are tied to a deployment definition. After a deployment changes, an existing session may receive a tool-list-changed notification and must list tools again before calling. Each MCP call has a fresh native idempotency key; repeating a JSON-RPC request ID is not a durable execution retry.

Automatic Mapping

Agent methods are automatically mapped to MCP entities based on the agent type and method signature:

AgentMethodMCP entity
SingletonNo parametersResource
Non-singletonNo parametersResource template
AnyHas parametersTool

Singleton agents (those with no constructor parameters) expose parameterless methods as MCP resources — static pieces of data that can be read by the client. Non-singleton agents expose parameterless methods as MCP resource templates, where the constructor parameters become template variables. Any method that takes parameters is exposed as an MCP tool that can be invoked by the AI model.

Method metadata

Method descriptions and prompt hints become MCP tool and resource metadata, helping AI models understand what each tool does and how to use it. TypeScript defines them with the description and promptHint properties of method(...); other SDKs use the corresponding language-specific annotations.

import { z } from 'zod'; import { defineAgent, method } from '@golemcloud/golem-ts-sdk'; export const CounterAgent = defineAgent({ name: 'CounterAgent', id: { name: z.string() }, methods: { incrementBy: method({ input: { value: z.number() }, returns: z.number(), description: "Add a value to the current counter", promptHint: "Increments the counter by the given value and returns the new count", }), }, }); export const CounterAgentImpl = CounterAgent.implement({ init: () => ({ count: 0 }), methods: { incrementBy({ value }) { this.count += value; return this.count; }, }, });

Security

MCP servers can be secured with OAuth2. Use the CLI to create a security scheme:

golem api security-scheme create mcp-oauth \ --provider-type custom \ --custom-provider-name "mock-oauth2" \ --custom-issuer-url "http://localhost:9099/golem" \ --client-id "golem-mcp-client" \ --client-secret "golem-mcp-secret" \ --scope openid --scope email --scope profile \ --redirect-url "http://mcp-demo.localhost:9007/mcp/oauth/callback"

Once the security scheme is created, reference it in the golem.yaml deployment to protect your MCP endpoints.

Special Data Types

Golem provides special data types that map naturally to MCP content types:

  • UnstructuredBinary — for binary blobs and images, mapped to MCP binary content
  • UnstructuredText — for text with MIME types, mapped to MCP text content
  • Multipart — for multipart data, supporting mixed content in a single response

These types allow agents to exchange rich content with MCP clients beyond simple JSON values.

MoonBit currently supports schema-native multimodal values through @multimodal.Multimodal[T] and #derive.multimodal, but does not yet provide user-facing UnstructuredText, UnstructuredBinary, or multipart wrappers. Use supported structured schemas or multimodal values instead; the removed #derive.text_languages and #derive.mime_types annotations are not available.

Testing with MCP Inspector

You can test your MCP server using the MCP Inspector :

npx @modelcontextprotocol/inspector node build/index.js

The inspector provides a web UI to browse available tools and resources, invoke them, and inspect the responses — useful for verifying your agent’s MCP interface before connecting it to an AI model.

Importing tools from another MCP server

mcp.deployments exposes Golem agents to external clients. In the opposite direction, mcp.imports makes an external MCP server’s tools available to Golem agents through the ordinary tool APIs and generated tool clients.

Declare imports in order for each environment:

mcp: imports: local: - url: https://tools.example.com/mcp prefix: catalog include: ["search*"]

Upstream names are sanitized to kebab-case before filtering. The prefix is joined with -, so search_items becomes catalog-search-items. Use either include or exclude, not both. Application tools and the selected environment’s ambient native tools take precedence over imports; among imports, earlier entries win. Imports do not need top-level tools declarations. The optional version selects the MCP protocol revision, not a tool release. The supported import protocol is currently 2026-07-28 Streamable HTTP.

Generate typed clients

Add the projected name to a component’s tool dependencies, using the component’s normal language template:

components: my-app:consumer: # Keep the component's existing dir, templates and build settings. dependencies: tools: [catalog-search-items]

golem build resolves the current manifest’s imports before generating the consumer’s tool clients. It does not use an older deployment’s declarations. Rust, TypeScript, Effect, Scala and MoonBit use their existing tool-client APIs. Unavailable metadata fails client generation rather than silently generating stale types. A changed projection causes regeneration on the next build. The generated client calls the projected canonical Golem name through tool-rpc; the upstream MCP name remains runtime metadata. Generated sources contain no MCP endpoint, direct MCP transport, or authentication credentials.

The result has a structured field and a content variant. If the upstream tool declares outputSchema, structured has that schema’s generated type. Otherwise it is optional JSON text. A single text, image or audio block uses stdout; its content descriptor carries the MIME type and annotations. Multiple blocks and resources stay ordered in content, without stdout. Embedded binary fields use the SDK’s unstructured-binary type. Empty content and an empty stdout payload are distinct cases. Use the SDK’s collection helper to consume stdout and the result concurrently.

Authorize an import before deployment

For OAuth, reference a configured security scheme using securityScheme on the import. Alternatively, configure auth.bearer or auth.basic (user and password); inline authentication and securityScheme are mutually exclusive. Keep credentials out of committed manifests and use environment-variable templates for secret values.

The calling agent needs network permission for the MCP endpoint and, when OAuth tokens must be refreshed, the provider’s token endpoint. Discovery and refresh consume the environment owner’s HTTP quota.

OAuth-protected imports need consent before generating typed clients. The environment and security scheme must already exist, but the import need not be deployed:

golem api mcp-import authorize 0 --manifest # Open the authorization URL, then copy the full callback URL. golem api mcp-import complete 0 --manifest '<callback-url>' golem api mcp-import status 0 --manifest

The index is zero-based in the selected environment’s import list. Keep the import declaration and its rendered environment variables unchanged between authorization and completion: consent is bound to that exact target. The CLI does not start a callback listener. These operations require permission to update the security scheme. Golem stores the grant under the environment owner’s account; the provider identity is the one used during consent.

For a deployed import, omit --manifest and use the revision printed by authorize when completing consent. --manifest and --revision are mutually exclusive. To revoke a grant, use golem api mcp-import disconnect 0 --manifest, or select a deployed revision instead. Redeploying alone does not grant consent.

Inspect and refresh deployed definitions

golem api mcp-import tools 0 --revision 42 golem api mcp-import refresh 0 --revision 42

Omitting --revision selects the environment’s current deployment. Inspection shows that import’s projected definitions before native and earlier-import precedence, plus reasons for excluded definitions. Explicit refresh reports upstream failures; ordinary reads can retain usable last-successful metadata. Cache misses fetch on demand, so periodic refresh is only an optimization.

Deployment attempts best-effort discovery using the operator’s permissions. It reports excluded definitions, collisions and unavailable metadata as warnings, without blocking a valid deployment or dropping its import declarations. These warnings do not guarantee that a later agent call has the necessary permissions or that the upstream definitions remain unchanged.

Durable invocations select imports from the deployment associated with the running agent and record the dynamic definition used. Completed tool calls replay their recorded results without contacting the MCP server or OAuth provider. An interrupted, incomplete call may be retried with the same derived idempotency key; avoiding duplicate upstream effects still requires the provider to honor that key.