Skip to content

Repository files navigation

odin-mcp

Model Context Protocol (stdio) server that calls odin-deployer-ent over REST (default 9000) and gRPC (default 8080), odin-scout-ent over REST (default 8080), and user-auth over REST (default 8081) for org/team/member APIs. Business logic stays in the Java services; this package is a thin adapter.

Protos are loaded at runtime from this repo’s proto/ directory (mirrors odin-deployer-ent’s src/main/proto). Imports such as google/protobuf/*.proto resolve against proto/google/protobuf/, populated from the google-proto-files npm package via npm run sync-google-protobuf (run after upgrading that devDependency). When the server API changes, update the copy under proto/ to stay in sync.

Prerequisites

  • Node.js 18+
  • For authenticated tools: a valid Authorization value (same as UserAuthClient.verifyToken). Use the full header value (often Bearer <jwt>).

Scout REST calls use the same resolved token unless ODIN_SCOUT_AUTH_TOKEN is set (override for Scout only).

Install & build

cd odin-mcp
npm install
npm run build   # produces dist/index.js (single bundled binary of JS deps)

Runtime artifact: dist/index.js embeds all npm dependencies (@grpc/*, @modelcontextprotocol/sdk, etc.). You do not need node_modules where the server runs—only Node 18+, dist/index.js, dist/package.json (written by the build so CommonJS resolution works under this repo’s "type": "module"), and the proto/ tree (same paths relative to the bundle’s parent directory; keep proto/ next to dist/ as in this repo).

Build tooling (esbuild, TypeScript, etc.) lives under devDependencies. If npm ci runs with NODE_ENV=production, devDependencies are skipped and npm run build will fail—use a builder stage without that flag, or npm ci --include=dev, until the bundle is produced.

To refresh vendored proto/google/protobuf after bumping google-proto-files:

npm run sync-google-protobuf

Environment variables

Variable Required Default Description
ODIN_DEPLOYER_REST_BASE No http://127.0.0.1:9000 REST base URL (no trailing slash)
ODIN_DEPLOYER_GRPC_HOST No 127.0.0.1:8080 gRPC host:port (GrpcVerticle)
ODIN_DEPLOYER_GRPC_USE_TLS No false If true, uses TLS with default trust store (no custom CA in v1)
ODIN_MCP_GRPC_STREAM_COMPLETION_DEFAULT No full Server-streaming gRPC tools only: full = wait for stream end; first_progress = return after first chunk (short chat round-trip; operation continues server-side — poll describe/status). Aliases: first / detach → first_progress; wait / complete → full
ODIN_DEPLOYER_AUTH_TOKEN For protected tools Sent on REST Authorization and gRPC metadata Authorization
USER_AUTH_REST_BASE No http://127.0.0.1:8081 user-auth Spring base URL (orgs, teams, invites). Same bearer as deployer; ODIN_SCOUT_AUTH_TOKEN overrides Scout REST only.
ODIN_DEPLOYER_REQUEST_TIMEOUT_MS No 300000 HTTP timeout (ms) — deployer, Scout, and user-auth REST
ODIN_SCOUT_REST_BASE No http://127.0.0.1:8080 Scout HTTP base URL (no trailing slash); include gateway prefix if mounted under e.g. /api
ODIN_SCOUT_AUTH_TOKEN No If set, Scout REST Authorization uses this instead of ODIN_DEPLOYER_AUTH_TOKEN / resolved MCP token

Do not commit real tokens or .env files.

Tools ↔ REST mapping

odin-deployer-ent

MCP tool Method Path / notes
deployer_health GET /healthcheck
deployer_operation_schemas_list GET /v1/operation-schemas/{component_type}/{deployment_type}
deployer_operation_schema_get GET /v1/operation-schemas/.../{operation_name}
deployer_component_catalogue GET /v1/component-catalogue (optional component_type)
deployer_component_operations GET /v1/component-operations
deployer_operate_component POST .../operateOperateRequest body
deployer_operate_status GET /v1/operate/status/{service_task_id}

odin-scout-ent

MCP tool Method Path / notes
scout_accounts_list GET /accounts — optional tool arg compact maps to ?compact=true
scout_account_details_get GET /account-details?accountName= — required tool arg accountName

user-auth (USER_AUTH_REST_BASE)

Uses USER_AUTH_REST_BASE and the same Authorization header as deployer (ODIN_DEPLOYER_AUTH_TOKEN or per-request overrides). Team routes require header X-Org-Id — pass org_id in the tool arguments (MCP sets the header).

MCP tool Method Path / notes
user_auth_health GET /healthcheck — no auth
user_auth_orgs_list GET /api/v1/orgs
user_auth_org_get GET /api/v1/orgs/{org_id}
user_auth_teams_list GET /api/v1/teams + X-Org-Idorg_id optional if Bearer JWT includes orgid
user_auth_team_get GET /api/v1/teams/{team_name} + X-Org-Id — same
user_auth_team_create POST /api/v1/teams body { name } + X-Org-Id — same
user_auth_team_members_list GET /api/v1/teams/{team_name}/members + X-Org-Id — same
user_auth_team_add_members POST .../teams/{team_name}/members body { emails: [] } + X-Org-Id — same
user_auth_org_members_list GET /api/v1/orgs/{org_id}/membersorg_id optional with org-scoped JWT
user_auth_org_invite_members POST /api/v1/orgs/{org_id}/members body { emails: [] } — same
user_auth_user_get GET /api/v1/users/{user_id}
user_auth_user_orgs GET /api/v1/users/orgs (current user’s orgs)
user_auth_team_update PUT /api/v1/teams/{team_name} body { name } + X-Org-Id
user_auth_team_transfer_owner PUT .../teams/{team_name}/owner — requires type_to_confirm = team_name
user_auth_team_delete DELETE /api/v1/teams/{team_name} — requires type_to_confirm = team_name
user_auth_team_remove_member DELETE .../teams/{team_name}/members/{email}type_to_confirm = email
user_auth_org_member_promote_admin PUT /api/v1/orgs/{org_id}/members/{email}/admintype_to_confirm = email
user_auth_org_member_set_role PUT .../members/{email}/role body { role }type_to_confirm = email
user_auth_org_member_remove DELETE /api/v1/orgs/{org_id}/members/{email}type_to_confirm = email
user_auth_org_update PUT /api/v1/orgs/{org_id} body { name }
user_auth_org_delete DELETE /api/v1/orgs/{org_id}type_to_confirm must equal org_id (digits)

The MCP server fills X-Org-Id from tool args org_id, or from the JWT orgid claim when the client uses an org-scoped access token (same as the Asgard dashboard after org selection). User-level tokens (no orgid) must pass org_id explicitly for these routes.

Destructive / high-risk user-auth tools require type_to_confirm: the user must explicitly agree in chat; the model passes the same team name, member email, or org id again so the MCP server can reject mistaken or automated calls. There is no HTTP API in user-auth to delete a whole user account from these controllers; use org/team member removal only.

Tools ↔ gRPC mapping

MCP tool RPC Notes
deployer_grpc_health grpc.health.v1.Health/Check No auth on server
deployer_grpc_list_tiers TierService/ListTiers Needs token
deployer_grpc_list_environment EnvironmentService/ListEnvironment Needs token
deployer_grpc_describe_environment EnvironmentService/DescribeEnvironment Needs token
deployer_grpc_create_environment EnvironmentService/CreateEnvironment Server-streaming; destructive. Optional arg stream_completion: first_progress returns after first chunk (use when IDE may drop long waits); default from env ODIN_MCP_GRPC_STREAM_COMPLETION_DEFAULT.
deployer_grpc_delete_environment EnvironmentService/DeleteEnvironment Server-streaming; destructive. Optional stream_completion (same as above).
deployer_grpc_status_environment EnvironmentService/StatusEnvironment Server-streaming; aggregated. Optional stream_completion.
deployer_grpc_list_services ServiceService/ListServices Needs token
deployer_grpc_describe_service ServiceService/DescribeService Needs token
deployer_grpc_deploy_service ServiceService/DeployService Server-streaming; deploy. Optional stream_completion.
deployer_grpc_operate_service ServiceService/OperateService Server-streaming. Optional stream_completion.
deployer_grpc_undeploy_service ServiceService/UndeployService Server-streaming; destructive. Optional stream_completion.
deployer_grpc_operate_component_diff ServiceService/OperateComponentDiff Unary
deployer_grpc_list_service_versions ServiceService/ListServiceVersions Unary
deployer_grpc_release_service ServiceService/ReleaseService Unary
deployer_grpc_check_service_release_name_unique ServiceService/CheckServiceReleaseNameUnique Unary
deployer_grpc_export_service ServiceService/ExportService Unary

Server-streaming RPCs return a JSON array of all messages received on the stream.

Cursor MCP configuration

Use absolute paths for Node and dist/index.js. If command: "node" fails with ENOENT, use the output of which node.

{
  "mcpServers": {
    "odin-mcp": {
      "command": "/full/path/from/which/node",
      "args": ["/absolute/path/to/odin-mcp/dist/index.js"],
      "env": {
        "ODIN_DEPLOYER_REST_BASE": "http://127.0.0.1:9000",
        "ODIN_SCOUT_REST_BASE": "http://127.0.0.1:8080",
        "USER_AUTH_REST_BASE": "http://127.0.0.1:8081",
        "ODIN_DEPLOYER_GRPC_HOST": "127.0.0.1:8080",
        "ODIN_DEPLOYER_AUTH_TOKEN": "Bearer <your-token>"
      }
    }
  }
}

Troubleshooting

  • SyntaxError: Cannot use import statement outside a module / MCP Connection closed: Prefer npm run build and run dist/index.js with dist/package.json from the same build (CommonJS bundle). If you use an older unbundled dist/*.js layout, ensure package.json with "type": "module" sits beside those files.
  • spawn node ENOENT: Use the full path to node in command.
  • 401 / 403 (REST) or gRPC permission errors: Fix token; confirm AuthFilter / AuthInterceptor rules.
  • Timeouts on operate: Increase ODIN_DEPLOYER_REQUEST_TIMEOUT_MS.
  • REST connection refused: Deployer REST on 9000 (ODIN_DEPLOYER_REST_BASE); Scout HTTP on 8080 (ODIN_SCOUT_REST_BASE); user-auth on 8081 (USER_AUTH_REST_BASE).
  • gRPC errors (UNKNOWN, UNAVAILABLE): Deployer gRPC on 8080; firewall; try grpcurl to the same host/port; set ODIN_DEPLOYER_GRPC_USE_TLS=true if the server uses TLS.

Development

npm run dev

Runs tsx src/index.ts (stdio; connect from an MCP host).

About

No description, website, or topics provided.

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages