DEV Community

MrOops
MrOops

Posted on

I Built Conciergent: Give Your MCP Tools a Slack, LINE, or Discord Chat Face, With Real In-Chat OAuth

A while back I built openapi-mcp-gateway, which turns any OpenAPI spec into an MCP server. That solved the supply side. But the people who most wanted those tools, product folks, support staff, ops, were never going to install Claude Desktop and paste a server URL into a config file. They live in Slack and LINE.

The real work was putting a chat face on those tools, one a non-technical person can just talk to. Once you try it, three things stop being optional very fast.

You need per-user auth that happens inside the chat, because you cannot send someone to a JSON config to complete an OAuth flow, and you certainly cannot let the whole team act as one shared service account. You need a confirmation step before anything destructive runs, because an LLM with write access to a real API will eventually try to do the wrong thing confidently. And you need replies that render natively on each platform, because a wall of Markdown that looks fine in one client is broken in the next.

By the time all three worked, I had Conciergent.

It connects to any Model Context Protocol server (or an OpenAPI spec directly) and turns it into a Slack, LINE, or Discord bot that can actually do things. Per-user OAuth is handled inside the conversation, destructive tools pause behind an approval card, and the agent emits one structured reply that each surface renders on its own. You point it at a YAML and it runs.

Who it is for matters as much as what it does. This is a bot you stand up for your users, each signing in as themselves, not a personal assistant you run for yourself.

Conciergent architecture, layered top to bottom. Chat surfaces (Slack, LINE, Discord, and more) sit on top. An incoming message flows down into a surface- and agent-agnostic runtime that produces one structured reply (plain text, a Card, or a Carousel). The runtime hands each turn to an AI agent powered by Pydantic AI, which resolves to a normal reply, an in-chat OAuth authorization, or a human-in-the-loop confirmation. The agent calls MCP tools (an OpenAPI spec via the embedded openapi-mcp-gateway, or any MCP server) and stores messages in Redis and credentials in Postgres. The reply flows back up to each surface.

Try It

uv add "conciergent[gateway]"
uv run conciergent init      # writes an annotated manifest.yml
Enter fullscreen mode Exit fullscreen mode

The scaffolded manifest.yml is a full config with the surface and store already wired up. Point the agent at an MCP server, or drop in an OpenAPI spec, set your Slack, LINE, or Discord credentials as env vars, and:

uv run conciergent run
Enter fullscreen mode Exit fullscreen mode

The fastest end-to-end path is the bundled Docker compose, which brings up Redis, Postgres, and the app together from one of the example configs:

cp examples/openapi-chat.yml manifest.yml
docker compose up
Enter fullscreen mode Exit fullscreen mode

Python 3.12+. Three model providers ship in the box (OpenAI, Google Gemini, Anthropic Claude). Set agent.model to a provider:model string and export that provider's key.

What Conciergent Actually Does

Three things, each shown in config.

1. Any MCP Server, or an OpenAPI Spec Directly

Most useful bots touch more than one thing. Point the agent at any MCP server URL:

# manifest.yml
agent:
  model: openai:gpt-4o-mini
  system_prompt: |
    You are a helpful assistant. Use your tools to answer the user's requests.
  mcp_servers:
    - http://localhost:9000/mcp
    - https://another-server.example.com/mcp
Enter fullscreen mode Exit fullscreen mode

And if what you have is a REST API rather than an MCP server, you do not need to run a second process for it. Add the gateway extra and Conciergent embeds openapi-mcp-gateway in-process, so a spec becomes MCP tools right there:

gateway:
  enabled: true
  specs:
    - name: petstore
      spec: https://petstore3.swagger.io/api/v3/openapi.json
      base_url: https://petstore3.swagger.io/api/v3
    - name: internal
      spec: ./internal-api.json
Enter fullscreen mode Exit fullscreen mode

Each spec is served at /{name}/mcp and wired into the agent for you, alongside anything already in agent.mcp_servers. A spec entry mirrors openapi-mcp-gateway's per-server config, so a large API can use exposure: dynamic (the agent sees three meta-tools instead of one per endpoint), a policy filter to keep endpoints away from the model, or auth.

2. In-Chat OAuth (The Constraint That Drove The Design)

This is the part that makes a chat bot different from an MCP client on your laptop. When a tool needs authorization, there is no config file to edit and no desktop app to bounce through. The user is in a Slack, LINE, or Discord DM, and the authorization has to happen right there.

So Conciergent runs the whole OAuth handoff inside the conversation. The first time a tool needs a token, the bot posts the authorization link into the chat. The user taps it, approves, and comes back to the same DM. Conciergent stores the token and refreshes it from then on, per user. Nobody leaves the conversation, and nobody shares one team-wide credential.

The same handoff covers an oauth2 spec behind the embedded gateway, so each user authorizes their own upstream account before its tools run. And because the flow is time-bounded, a slow authorization expires cleanly instead of hanging the request.

Tokens persist in Postgres, so a redeploy does not sign everyone out. Chat history lives only in Redis, kept just long enough for context before it expires on its own, along with the other transient state (approvals, the pending handoff). Nothing a user says is retained past that window.

3. An Approval Gate, and One Reply That Renders Everywhere

Two problems, one design.

Human-in-the-loop. Any tool the MCP server marks destructive pauses behind a Confirm / Cancel card before it runs. The model proposes the action, and the human commits it. A pending approval has its own TTL, so an ignored card does not sit forever holding a write open.

Surface-agnostic replies. The agent never speaks Slack, LINE, or Discord. It emits one of three shapes, and each surface renders it natively:

  • str for plain text.
  • Card for a header, text sections, an optional hero image, a footnote, link buttons, and suggestion quick-replies.
  • Carousel for a small set of option cards the user picks between.

A suggestion is the interactive primitive. Tapping one posts its prompt back to the agent as if the user had typed it. The field descriptions on these models are the agent's structured-output schema, so the model fills them in directly and the same reply object renders correctly on Slack, LINE, and Discord.

UI text (buttons, prompts, greetings) is not hardcoded either. It lives in a locale catalog, picked from each user's platform language, so the bot answers people in their own language with no per-message translation calls.

How It Compares

The question that sorts this field is not which agent has the most features, but who the bot is for. Conciergent is built for a service provider who wants to give their own users a bot on the Slack, LINE, or Discord those users already have. Most of the projects it gets compared to are built for someone else, so they make different trade-offs. Two groups come up the most:

  • Personal assistants like Hermes Agent and OpenClaw. You run one for yourself and reach it from any chat app. They do far more than Conciergent (voice, memory, self-improving skills, dozens of channels), but each install serves a single owner with a single set of credentials, so there is no notion of separate end-users.
  • Self-hosted AI platforms like Dify, Open WebUI, and LibreChat. They overlap the most, with multi-tenant deployments, per-user OAuth, native MCP, and heavy maintenance. But your users reach them in the platform's own web app. Getting onto Slack or Discord means a relay that pipes that web-app chat into the DM, text-first, with no native cards and no per-user OAuth in the conversation.
Conciergent Personal assistants Self-hosted AI platforms
Built for Your users Just you Your users
Surface Their Slack / LINE / Discord 20+ chat apps Its own web app
Separate end-users Yes No In web app
Per-user OAuth Yes, in chat No Yes, in its web app
Native cards and carousels Yes, per surface Text-first Web app only
Approval gate Yes Yes Partial
MCP and OpenAPI to tools Both MCP only Both

The assistants that reach these surfaces run for a single owner, and the multi-tenant platforms stay in a web app. Neither puts a per-user bot with native replies in the chat itself.

It fits three situations in particular:

  • Internal tools for non-technical teammates. Support, ops, finance. They will never open an MCP config, but they will DM a bot. Point Conciergent at your internal MCP server (or spec) and they talk to it.
  • Anything where actions must happen as the actual user. Approving a request, moving a record, closing a ticket on someone's behalf, where the upstream audit log has to show the human. The in-chat per-user OAuth handles that end to end.
  • A REST API you want to demo as a chatbot fast. Enable the gateway, drop in the spec, and you have a Slack, LINE, or Discord bot over it with no second server to run.

What Is And Is Not There Yet

Everything above ships today.

From here, the main line of work is more surfaces. Each one is a single class behind the surface contract, with the runtime and agent unchanged, so the list keeps growing without a rewrite. Telegram and Teams are next. If your platform or use case is not there yet, open an issue with the shape of your problem. Concrete use cases drive the design more than my guesses.

Closing

Conciergent is the companion to openapi-mcp-gateway. The gateway turns a REST API into MCP tools, and Conciergent gives those tools a chat face. Together they take one or more OpenAPI specs all the way to a bot your users can talk to. Like the gateway, this is a personal open-source side project. Sharing it here in case the situations above sound like yours.

Top comments (0)