Skip to content

BimRoss/agents-mcp-server

Repository files navigation

agents-mcp-server

Thin runtime for the squad (alex, anna, garth, joanne, ross, tim): every inbound message is handled as a bounded multi-step task by mudler/cogito against tools/list from skills-mcp-server, plus a built-in direct_reply tool (no MCP). The router may chain MCP tools (for example read_web then create_google_doc) before finishing with direct_reply. Ordering is model-chosen within the step cap, with one narrow deterministic exception: research-heavy Google Doc follow-ups (title/editor + paper/pages/research cues without repeating “google doc”) trigger a single injected read_web before the first model step so thread-only text still gets grounding.

JetStream consumes slack.work.*.events (one subject per employee, e.g. slack.work.joanne.events). Set each employee’s *_SLACK_BOT_TOKEN so NATS replies post as the right bot.

Startup requirements

The process exits at startup unless:

  • GEMINI_API_KEY and/or AGENTS_ROUTER_API_KEY resolves to a non-empty router key (see below), and
  • AGENTS_ROUTER_DISABLED is not true.

How a turn runs

  1. tools/list from skills-mcp-server → register MCP tools + direct_reply as OpenAI-style tools.
  2. Loop (max AGENTS_ROUTER_MAX_TOOL_STEPS, default 8, hard cap 20): each iteration is one OpenAI-compatible chat/completions call with tool_choice: required (Gemini default base URL when using GEMINI_API_KEY only).
  3. direct_reply → render straight to Slack and stop. Any other tool → tools/call on MCP; the tool result JSON is appended to the chat for the next iteration so the model can plan the following step.
  4. On the last iteration, the server appends a short user nudge and sets tool_choice to direct_reply only so the task always ends with a Slack-visible message.

State: in-memory thread store only. Optional lightweight local debug UI at /.

Credentials (router LLM)

Priority Env Role
1 AGENTS_ROUTER_API_KEY OpenAI-compatible API key when set (optional if Gemini key exists).
2 GEMINI_API_KEY Used when AGENTS_ROUTER_API_KEY is empty. Defaults AGENTS_ROUTER_BASE_URL to https://generativelanguage.googleapis.com/v1beta/openai/ and AGENTS_ROUTER_MODEL from GEMINI_MODEL (default gemini-2.5-flash).
Override AGENTS_ROUTER_BASE_URL, AGENTS_ROUTER_MODEL Force provider/model regardless of source key.

OpenAI-style routing without Gemini: set AGENTS_ROUTER_API_KEY and optionally AGENTS_ROUTER_BASE_URL / AGENTS_ROUTER_MODEL (defaults to gpt-4o-mini when not using the Gemini-only resolution above).

Environment

Copy .env.dev.example.env.dev in each repo that participates in the stack (gitignored):

Repo File
agents-mcp-server .env.dev
skills-mcp-server .env.dev
slack-orchestrator .env.dev
makeacompany-ai .env.dev

agents-mcp-server keys include:

  • SKILLS_MCP_URL — MCP endpoint for skills-mcp-server (…/mcp).
  • AGENTS_NATS_URL — when set, starts a JetStream push consumer on slack.work.*.events (same stream as slack-orchestrator). Compose sets nats://nats:4222 for the full stack.
  • AGENTS_NATS_CONSUME_NEW_ONLY — default true; consume only newly published JetStream events (prevents old backlog replay on restart).
  • AGENTS_NATS_MAX_EVENT_AGE_SEC — default 300; drops stale events older than this threshold by JetStream publish time and Slack message_ts.
  • AGENTS_ROUTER_MAX_TOOL_STEPS — default 8; max tool invocations per user message (including direct_reply). Capped at 20.
  • AGENTS_SLACK_POST_FROM_NATS — default true; when false, inbound NATS turns still run the router but skip chat.postMessage.
  • ALEX_SLACK_*, ANNA_SLACK_*, GARTH_SLACK_*, JOANNE_SLACK_*, ROSS_SLACK_*, TIM_SLACK_* — per-employee bot (+ optional app) tokens for JetStream thread replies. Check GET /api/status (slackEnvPresent, natsEnabled, routerModel, routerKeySource).

Per-service env files: docker-compose.yml uses each sibling repo’s .env.dev via env_file (no Compose ${VAR} interpolation). docker-compose.yml still overrides ORCHESTRATOR_NATS_URL, ORCHESTRATOR_DISPATCH_ENABLED, and ORCHESTRATOR_TERMS_REDIS_URL on the orchestrator container so local JetStream targets the compose NATS broker and terms gate stays off unless you set Redis in slack-orchestrator/.env.dev.

Joanne #humans terms gate: omit ORCHESTRATOR_TERMS_REDIS_URL (compose sets it empty) so all human messages route without acceptance checks. Set Redis only when you want prod-like terms enforcement.

Local startup

From this directory:

cp .env.dev.example .env.dev
cp ../skills-mcp-server/.env.dev.example ../skills-mcp-server/.env.dev
cp ../slack-orchestrator/.env.dev.example ../slack-orchestrator/.env.dev
cp ../makeacompany-ai/.env.dev.example ../makeacompany-ai/.env.dev
# Min: GEMINI_* in skills + agents for router; per-employee Slack tokens in agents; orchestrator tokens in slack-orchestrator; Stripe/Google/Resend in makeacompany-ai as needed.
docker compose --profile local up --build

Services (profile local):

Service Port Role
skills-mcp-server 8081 MCP tools (read_web, skill FS tools, …)
agents-mcp-server 8090 HTTP /api/chat, JetStream consumer on slack.work.*.events, optional Slack thread replies
nats 4222 (8222 monitoring) JetStream broker shared with slack-orchestrator
slack-orchestrator 8080 Slack ingress → NATS only (compose disables Tier-1 / semantic tool routing; routing stays in agents + MCP)

Without NATS, run only skills + agents and unset AGENTS_NATS_URL (compose sets it when using the full stack).

Kubernetes (admin cluster)

Each app keeps production material in its own .env.prod (gitignored). Sync is runtime-only (Secrets in the cluster); GitOps image pins stay on tag-driven CI per rancher-admin.

App Repo Command (from that repo) Secret / namespace
agents-mcp-server this repo ./scripts/update-rancher-secrets.sh agents-mcp-server-runtime / agents-mcp-server
skills-mcp-server skills-mcp-server ./scripts/update-rancher-secrets.sh skills-mcp-server-runtime / skills-mcp-server
slack-orchestrator slack-orchestrator ./scripts/update-rancher-secrets.sh slack-orchestrator-runtime / slack-orchestrator
makeacompany-ai makeacompany-ai ./scripts/update-rancher-secrets.sh makeacompany-ai-runtime-secrets / makeacompany-ai

Use export KUBECONFIG="${HOME}/.kube/config/admin.yaml" and kubectl --context admin … when your default context is not admin.

Verify after apply: kubectl --context admin -n <ns> get secret <name> -o jsonpath='{.data}' only shows base64 key names; confirm pods pick up changes with kubectl --context admin -n <ns> rollout status deploy/<deploy> or ROLLOUT_RESTART=true where the script supports it (agents-mcp-server, slack-orchestrator; skills-mcp-server script restarts its deployment by default; makeacompany-ai restarts backend+frontend by default).

Cross-service consistency: e.g. BACKEND_INTERNAL_SERVICE_TOKEN / AGENT_FACTORY_ADMIN_TOKEN must match what makeacompany-ai and employee-factory scripts document—rotating one surface without the others yields 401s, not a broken kubectl apply.

HTTP API

  • GET /health
  • GET /api/status
  • POST /api/chat

Example:

curl -s http://localhost:8090/api/chat \
  -H "content-type: application/json" \
  -d '{"agent":"ross","message":"latest updates on model context protocol standard","threadId":"demo"}'

About

No description, website, or topics provided.

Resources

Stars

Watchers

Forks

Packages

 
 
 

Contributors