Skip to content

Claude connector (MCP)

CompassDocs ships a built-in MCP server at /api/mcp. Connect it to the Claude desktop app and Claude can search your knowledge base, read documents, create new articles as markdown, and revise existing ones — all as you, with your CompassDocs role and your workspace’s approval rules.

Typical flow: brainstorm and draft an article with Claude in the desktop app, then say “save that to CompassDocs in the Engineering space” — done. Later: “pull up the runbook we wrote last week and tighten the intro”.

In the Claude desktop app (or on claude.ai with a paid plan):

  1. Settings → Connectors → Add custom connector
  2. Paste your CompassDocs MCP URL: https://YOUR-COMPASSDOCS-HOST/api/mcp
  3. Click Add, then Connect — your browser opens CompassDocs, you sign in (if you weren’t already), and click Approve.

That’s it. CompassDocs ships its own OAuth authorization server, so Claude registers itself, you approve once in the browser, and tokens are issued and refreshed automatically — nothing to copy, no config files. Manage or disconnect apps anytime under Manage account → API tokens → Connected apps.

Alternative: personal API token (any MCP client)

Section titled “Alternative: personal API token (any MCP client)”

For MCP clients without the one-click flow, use a personal token instead:

  1. In CompassDocs: Manage account → API tokens → create a token (shown once; the page includes a ready-made config snippet).
  2. In Claude Desktop’s claude_desktop_config.json (requires Node.js for npx):
{
"mcpServers": {
"compassdocs": {
"command": "npx",
"args": [
"-y",
"mcp-remote",
"https://YOUR-COMPASSDOCS-HOST/api/mcp",
"--header",
"Authorization: Bearer cdk_YOUR_TOKEN"
]
}
}
}
Tool Who can use it What it does
list_spaces everyone Spaces with slugs, to file new docs correctly
list_docs / search_docs everyone Browse or full-text search (viewers see published only)
read_doc everyone Full markdown body plus metadata — including path, sub-pages, and backlinks when nested pages & backlinks are enabled, and, on a document that requires read confirmation, the standing (“42 of 50 people have confirmed v12”, or “1 of 1 person has confirmed v3” when one person is eligible) and a reminder that editing its text needs ack_policy
writing_guide everyone The full authoring reference — every rich block with exact syntax
list_templates everyone The workspace’s document templates with their full scaffolds
create_doc editor + New document from markdown — drafts by default; pass template to use a template’s structure, type, and tags
update_doc editor + Replace body / metadata, change type, move spaces, or publish — with a version note; on a document that requires read confirmation, a change to the body or title needs ack_policy (keep or reset) and ack_reason
add_image editor + Put an image on a document — fetched from a URL, copied from another attachment, or base64 — and optionally place it in the body in the same call
request_upload editor + Mint a single-use link a person can drop an image file into, for a picture Claude can’t send itself
create_training_deck training manager Turn a published doc into a training deck (enterprise training entitlement)
assign_training training manager Assign a deck by usernames or to everyone — assignees are notified
training_status training manager Deck list with completion counts, or one deck’s per-person status incl. quiz scores
list_handbooks everyone The handbooks you can read and the drafts you can edit, with your progress
read_handbook the handbook’s readers and editors A handbook as its reader shows it, or one document in it
handbook_status the handbook’s readers Where you stand on each document in a published handbook, and on the handbook as a whole
create_handbook Build handbooks A new handbook, always as a draft
update_handbook_contents the handbook’s editors Replace its sections and documents; live at once on a published handbook
hd_* (19 tools) depends on the tool The helpdesk (Enterprise, 1.19.1): requests, tickets, reports and drafts

Claude writes with the full editor toolbox

Section titled “Claude writes with the full editor toolbox”

The connector isn’t limited to plain markdown. The writing_guide tool hands Claude the same block vocabulary the in-app editor offers — callouts, tabs, accordions, interactive checklists, Mermaid and PlantUML diagrams, decision trees, video and website embeds, and auto-filterable tables — with exact syntax, and the server instructions tell Claude to consult it before writing. Ask Claude for a runbook with a decision tree and platform tabs, and the document it saves renders those blocks interactively in the app, just as if it had been written in the editor.

Getting a picture into a document is the one thing an assistant is worst at, and the reason is worth knowing: Claude usually cannot send you the bytes.

A screenshot you paste into a conversation reaches Claude as an image it can see, not as a file it holds. There is no byte-level copy for it to re-emit, so asking it to “upload that screenshot” cannot work no matter how the request is phrased. Separately, base64 encoding inflates a file by a third, so even a file Claude can read is usually far too large to fit inside a single tool argument — a 300 KB screenshot becomes ~400,000 characters.

From 1.1 there are four ways in, and Claude picks between them:

Route When it’s used
source_url The image has a public address. Your server fetches it, so size stops mattering. This is the best route whenever it applies.
from_attachment_id The image is already attached to a document in this workspace. It’s copied onto the new document, so deleting the original never blanks the copy.
request_upload The picture only exists as something you can see or have on disk. Claude gives you a link to drop it into (below).
data Raw base64. Still supported, still fine for small files.

PNG, JPEG, GIF, and WebP are accepted — the type is sniffed from the bytes, so a mislabelled .png is refused rather than rendering broken, and SVG is rejected. The image is stored as a normal document attachment, capped by the workspace attachment size limit.

add_image takes an insert option: "append" puts the image at the end of the document, "top" at the beginning, and "none" (the default) returns just the markdown snippet for Claude to place itself. Appending edits only the text around the image, so it is safe against someone editing the same document at the same time.

Ask for “add this to the runbook” and you get the image in the runbook, not an attachment you then have to ask about again.

When Claude can’t produce the file — the screenshot-in-the-chat case — it calls request_upload and hands you a link like https://docs.example.com/upload/mBvR…. Open it, drag the file in (or paste it, or browse for it), and the image is attached to the document and placed in the body automatically. Nothing further to ask Claude for.

The page needs no sign-in on purpose: the screenshot is usually on your phone while Claude is running on your laptop. Each link is:

  • single-use and tied to one document
  • valid for one hour
  • image-only, through the same type check as every other route
  • minted only by someone who already had edit rights on that document — and the upload is recorded in the audit log as that person

If a link is expired or already used, the page says so plainly rather than accepting a file that would go nowhere. Ask Claude for a new one.

The connector goes through exactly the same rules as the app:

  • Creating: new docs are drafts unless you ask Claude to publish and your role (or open approval mode) allows it — otherwise they stay drafts.
  • Editing a published doc as an editor in strict mode files a change request into the review queue instead of touching the live page. Claude is told this and will relay it.
  • Publishing a draft (update_doc with publish) works the same way: approvers and admins publish immediately; an editor’s publish request is queued for review in strict mode.
  • Editing a policy (a document that requires read confirmation): when the body or title changes, or publish puts a draft live whose text differs from the version people confirmed, update_doc needs ack_policy (keep = editorial fix, confirmations stand; reset = material change, everyone is asked to re-confirm and told) and ack_reason (a reset needs a reason of at least 10 characters; a keep follows Program settings’ Require a reason for editorial fixes too). Without them Claude gets a result with decision_required: true and the numbers: confirmations and eligible (42 of 50), baseline (the version people confirmed, “v12”), change (the measured difference: the percentage of words, and the words, blocks, headings and numbers that changed) and suggested (what that measure calls it, keep or reset), plus a hint to ask you which it is and why; nothing is saved until it calls again with your answer. Metadata changes never ask (a wrong ack_policy value is still refused). The decision lands on the policy’s History tab with source MCP and your name, exactly as an edit in the app would. Claude cannot confirm a document on your behalf: there is no tool for it, by design.
  • Adding an image (add_image, request_upload) requires edit rights on the document’s space, exactly like editing it — and every upload is audited, including images that arrive through a drop link. The alt text (or the file name standing in for it) is kept to one line with no markdown in it, so the document gains exactly one image line and nothing else.
  • Every action lands in the audit log, marked as coming via the connector, with the caller’s IP address.

From 1.18.2 Claude can read your policy handbooks, tell you where you stand on one, and build draft handbooks for a person to review and publish. Five tools do it, and each works with your access, exactly as the app does. Ask, for example:

  • “Which handbooks do I still have to confirm?”
  • “Summarise the remote access section of the security handbook.”
  • “Build a draft onboarding handbook for the Support space from our published SOPs, in three sections.”
  • “Move the travel policy into the Expenses section of the employee handbook.”

Handbooks are part of every edition. Your standing and the audience’s progress need read confirmation, which needs the enterprise image and a license with the Policy acknowledgements entitlement; without it the answers say confirmation isn’t available, and handbooks are for reading. Like every tool here, these need a read + write token: the connector refuses a read-only token outright.

Lists the handbooks you can read and the drafts you can edit, each with its id, title, owner (the whole workspace or a space), status, how many documents and sections it holds, when it was last updated, and whether it asks to be confirmed as a whole. Two optional arguments narrow it: space, a space’s slug (from list_spaces) or workspace for workspace handbooks, and status, draft or published.

With read confirmation licensed, a published handbook also shows your own progress (3 of 8 confirmed) when any of its documents asks you. Its editors, and people who hold Read compliance program, also get the audience progress the Handbooks page shows for a handbook that asks to be confirmed as a whole.

Reads a handbook as its reader shows it: the introduction, then the sections in order, and each numbered document with its type, its facts (Owner, Approved by, Version, Effective, Next review, Applies to), its In short points, its text as markdown and its address in the reader. Pass the handbook’s id; add doc_id to read one document in it, or include_text: false for an outline of titles, facts and In short points without the text.

Access is the reader’s. A published handbook opens every published document in it to its audience, even from a space they can’t open, as the reader does. A draft is its editors’ alone. An editor sees a document from a space they can’t add from only as “A document you can’t open”, with its id and nothing else, and a document still in draft is listed without its text.

A whole handbook is answered within a text budget of 150,000 characters. Documents get their text in reading order until the next one would go past it; that one and every one after it come without their text, and the answer names their ids, so Claude reads each one with doc_id.

Where you stand on a published handbook: each document as To confirm, Confirmed, Updated since you confirmed or For information, your progress, and, when the handbook asks to be confirmed as a whole, whether your whole-handbook confirmation is on record for the handbook as it stands now. Its editors, and people who hold Read compliance program, also get the share and number of the audience who confirmed it, without names. Pass the handbook’s id. On a draft the answer says readers are asked once it is published.

Creates a workspace or space handbook, always as a Draft. It needs Build handbooks for the owner you choose: held globally for a workspace handbook, or on that space for a space handbook (see Who builds handbooks). Its arguments, in plain words:

  • title, required, up to 160 characters, and introduction, Markdown shown before the first document, up to 20,000 characters.
  • owner: workspace (the default), or a space’s id or slug.
  • audience: all (the default: everyone, or everyone who can read the space) or groups, with groups naming them (below).
  • confirm_whole and require_signature: the editor’s Ask readers to confirm the whole handbook and Require a typed signature, both off unless asked.
  • sections: optional first contents, in order, each with a title (up to 120 characters) and its published document ids in reading order; up to 50 sections and 200 documents, each document once. A document must be one you could add in the editor: from any space you can see for a workspace handbook, from the spaces where you build handbooks for a space handbook.

Groups are passed by name or by id. A name matches whatever its case, and must name one group: a name two groups share is refused, with their ids, so Claude passes the id of the one you mean. A number, or a name made only of digits, is always read as an id, so a group whose name is all digits is passed by its id. Publishing for chosen groups needs at least one.

Everything is checked, with the same permission, checks and limits as New handbook, before anything is written, so a document you can’t add creates nothing. The tool never publishes: the answer gives the editor’s address, /handbooks/{id}/edit, where a person reviews the draft and publishes it.

Replaces a handbook’s contents, its sections in order and each section’s documents in order, with the checks of the Contents card’s Save. It needs the right to edit the handbook.

  • sections: the whole contents, 1 to 50 sections and up to 200 documents. A section or document left out is removed. A section sent with its id (from read_handbook) stays that section; one without an id is new. A placeholder (“A document you can’t open”) is kept by sending its id. A document new to the handbook must be published and from a space you may add from.
  • if_updated_at: the handbook’s updated_at as Claude last read it. If someone saved the handbook after that, the save is refused and nothing is written (“Someone else saved this handbook since you read it”); Claude reads it again and makes the change on the current contents. The answer gives the new updated_at. It is optional, but without it a save overwrites whatever is there, so Claude is told to send it.
  • find_modes: optional, sets Where people find it for documents in the contents sent: space (Space + handbook) or handbook_only. As in the editor’s menu, it needs Build handbooks on each document’s own space, and it is stored on the document, so it holds in every handbook the document is in. Each document once, up to 200. These are checked before the contents are saved, so a refusal saves nothing.

On a published handbook the change is live for its readers at once, as Save is. The tool never publishes or unpublishes a handbook, and it leaves the details (title, owner, audience and the switches) alone: those stay in the editor.

No connector tool confirms a handbook or a policy. Confirmation is the person’s own, made in the app, and the answers say where: the whole-handbook page, /handbooks/{id}/confirm, or each document’s own page in the reader. Ask Claude to confirm for you and it can only give you the link.

Handbook changes made through the connector are audited as the editor’s are, as handbook.created, handbook.contents_changed and handbook.find_mode_changed, each with via: "mcp" in its details and the caller’s IP address (see In the audit log). If create_handbook made a draft but could not save its first sections, it removes the draft again, and that is a handbook.deleted entry marked the same way.

From 1.19.1 Claude can work in the helpdesk: raise and follow your own requests, help agents read and answer tickets, and draft workflows, request types and macros for admins. Ask, for example:

  • “My laptop won’t charge. Is there a guide, and if not, raise a request with IT.”
  • “Where are my open requests up to?”
  • “Summarise #1047 and draft a reply asking for the serial number.”
  • “Which urgent tickets in IT have nobody on them?”
  • “Draft a request type for parking permits, with a start date and a car registration.”
  • “Draft a reply to #1047 using our VPN re-pairing canned response.”

The helpdesk tools need the enterprise image and an Enterprise license; without them the tools answer that the helpdesk isn’t available. Claude always acts as you, with your workspace permissions, your desk role and your teams: it sees exactly what you would see in the app, goes through the same checks and limits, and can never do more than you could. Requesters never see internal notes through Claude. Like every tool here, these need a read + write token.

Anyone with the Get help permission:

Tool What it does
hd_request_types The request types you may use, with their form questions and what happens next, including who approves. Pass a type’s slug for its full form, with answers filled in from your directory entry.
hd_suggest_articles Documents you can read that may already answer the question. Claude offers these before raising a request.
hd_create_request Raises a request, as Get help would. With a request type, the answers are checked like the form. Returns the request number and its link. Claude confirms the details with you first.
hd_my_requests Your requests and the requests you are copied on, newest first, with their status and current step.
hd_read_request One of your requests (or one you are copied on, or approve): status, progress, answers and the public conversation. Never internal notes, drafts or replies waiting for review.
hd_reply_to_request Adds your own public reply to your own request, or one you are copied on, as you would in Get help. A request waiting on you, or solved, opens again. An agent who works the ticket replies from the desk instead.
hd_my_approvals The approvals waiting for your decision, with the request’s answers, and a link to each one.

Anyone who works the desk (Work helpdesk tickets and a desk role):

Tool What it does
hd_queue Tickets in your queues, by view, team, status, priority, assignee, requester, tag, missed target or text. Also lists your teams.
hd_read_ticket The whole ticket: fields, reply targets, the conversation with internal notes, answers, workflow progress and hand-offs, the requester’s contact card (directory visibility applies), who it can be assigned to, any reply drafts waiting, (1.19.2) its checklists, with which items are required and done, and (1.19.3) its linked assets from Snipe-IT (from 1.19.4 also Microsoft Intune), each with its status, who has it, warranty end and earlier tickets.
hd_add_internal_note Adds an internal note. Needs Add internal notes.
hd_draft_reply Saves a reply draft on the ticket for an agent to check and send in the desk (see Drafts in the desk). It is never sent.
hd_update_ticket Changes status, priority, team, assignee or tags, each within your desk role. Only when the workspace lets Claude update tickets. From 1.19.2 it can’t solve a ticket whose required checklist items aren’t ticked: it is refused with the same sentence the desk shows (“Finish the required checklist items first: …”).
hd_canned_responses (1.19.2) The canned responses you can insert (your teams’, the workspace’s and your own), read only; filter with query. Given a ticket number you work, each also comes back filled in for that ticket (requester’s name, ticket number, team, your name), ready for a reply draft. Offered at every workspace level, Read only included, and never counted as a use.
hd_asset_lookup (1.19.3) Finds assets synced from Snipe-IT (and from 1.19.4 Microsoft Intune, with each device’s compliance and last check-in) by tag, serial, name, model, the name of the person who has it or their exact email address (query, limit 1 to 20), each with its status, who has it, location, warranty end, how many tickets it is linked to and its link in Snipe-IT. Read only, and offered at every workspace level. Every asset while Agents can search all assets is on, otherwise only those of people whose tickets you work. While Snipe-IT is disconnected, only assets linked to tickets, with a notice saying so. Linking an asset to a ticket is done in the desk.
hd_ticket_summary The material for a summary (the conversation in order, notes marked, answers, where its workflow is) and similar past tickets from your queues. Claude writes the summary; nothing is saved.
hd_report Headline numbers for a period: created, solved, median first reply and resolution, targets met and satisfaction, split by team, agent and category. The whole helpdesk needs All reports, one team Team reports, and your own stats Their own stats.

Each needs the desk capability shown, and saves a draft for a person to publish in the app:

Tool Needs What it does
hd_list_workflows Workflows The workflows, published or not, with their open runs and request types; pass an id for one workflow’s steps.
hd_draft_workflow Workflows Creates a workflow, or saves new steps as the draft of an existing one. Running and new requests keep the published version until someone publishes the draft in the workflow builder; the answer links to it.
hd_draft_request_type Request types Drafts a request type and its form. It is saved switched off, so nobody sees it in Get help until someone reviews it and switches it on in Desk settings → Request types.
hd_draft_macro Personal macros Drafts a macro, saved as your personal macro. Share it with a team or everyone in Desk settings → Macros.

Whatever the settings, and whoever asks, no tool exists for these:

  • Send a reply to a requester. Claude saves a draft and a person sends it.
  • Approve or decline. Claude lists what’s waiting and links to the approval; you decide in the app.
  • Publish a workflow, request type or macro. Claude saves a draft for someone to publish.

Requesters replying on their own requests (hd_reply_to_request) is the one public message Claude writes, and it is your own reply, which Claude confirms with you first.

Desk settings → Claude connector (desk capability Helpdesk settings) sets how far Claude may go for everyone who connects it. It only ever narrows what each person could do themselves.

Claude can Means
Read only Find and read requests and tickets the person can see, and summarise them.
Read, add internal notes and save reply drafts (the default, recommended) Also internal notes, reply drafts, the person’s own requests and replies on them, and drafts of workflows, request types and macros.
Also update tickets Also status, priority, team, assignee and tags, within the person’s desk role.

Tools a level doesn’t allow aren’t offered to Claude, and each call is checked again. Asked for something the level doesn’t allow, Claude is told the workspace’s setting and that nothing was saved.

The page also lists the never-list above (Never, whatever the setting) and Recent activity via Claude: each note, draft, request and change Claude saved, who for and when (“Saved a reply draft on #1047”).

A reply Claude drafts waits on the ticket, above the composer, as Draft from Claude: who asked for it and when, “not sent”, and how many older drafts are waiting.

  • Use as reply moves the draft into the reply box (after anything you had already typed), so you can edit it and Send it yourself. Your send follows the normal rules: a newbie’s reply still goes for review.
  • Discard removes it.

Only agents who work the ticket see drafts. Requesters and CCs never do. Saving a draft is never held up by the collision warning; the agent’s own Send afterwards is, if someone replied in the meantime.

On a merged ticket, which is read-only, Claude can’t add a note, save a draft or change the status: it is told which ticket the merge kept.

From 1.19.4, a ticket in the recycle bin is hidden from every helpdesk tool, for requesters and agents alike: it isn’t listed, searched or counted, and asking for it by number answers as for a ticket that doesn’t exist. It comes back once it is restored. No tool deletes or restores tickets.

The helpdesk REST API (1.19.4) is the better fit for scripts: its GET /reports/summary gives the same numbers as hd_report.

“via Claude” on the timeline and in the audit log

Section titled ““via Claude” on the timeline and in the audit log”

Notes, replies on your own requests and ticket changes made through Claude say via Claude on the ticket’s timeline (“Priya changed the status from Open to Solved via Claude”), so everyone can tell. Every write is in the audit log, as the person who connected Claude, with via: "mcp" in its details and the caller’s IP address:

Action Shown as
helpdesk.request.created Raised a request
helpdesk.request.replied Replied on own request
helpdesk.note.added Added an internal note
helpdesk.reply_draft.created Saved a reply draft
helpdesk.ticket.updated Changed a ticket
helpdesk.workflow.created / .updated Created / Edited workflow
helpdesk.request_type.created Created request type
helpdesk.macro.created Created macro

An agent using or discarding a draft in the desk is recorded as helpdesk.reply_draft.used (Used a reply draft) and helpdesk.reply_draft.discarded (Discarded a reply draft).

  • The token travels in an Authorization header over HTTPS — use a proper HTTPS deployment (see Custom domain & HTTPS if you haven’t set that up).
  • One-click connections use short-lived OAuth tokens with automatic rotation; personal tokens are long-lived — one per device/app is good hygiene. Both are listed (with last-used times) and revocable on the tokens page.
  • The same endpoint works with any MCP client, not just Claude Desktop.
  • From 1.18.0 list_spaces, list_docs, search_docs and the sub-pages and backlinks read_doc reports leave out handbook-only documents in spaces the token’s user can’t write in, as the app does. From 1.18.2 the handbooks themselves are on the connector: see Handbooks.

Troubleshooting: “Authorization failed”

Section titled “Troubleshooting: “Authorization failed””

If the one-click connector fails at the sign-in step with a generic “Authorization with … failed”, “unable to connect to the sign-in service” (or an ofid_… reference), the OAuth handshake couldn’t complete. Claude’s servers reach your server over the public internet, fetch its discovery documents, and complete the token exchange — so the usual cause is that the discovery metadata advertises URLs Claude can’t use.

Start with the built-in check: Settings → System → Diagnostics has a Claude connector (MCP) row that shows exactly which sign-in URL your install advertises, probes it from the server, and says what to fix — a plain http:// issuer, a stale custom domain, or a reverse proxy that isn’t forwarding X-Forwarded-Proto.

To verify from the outside too, run this from any machine outside your network:

Terminal window
curl https://YOUR-COMPASSDOCS-HOST/.well-known/oauth-authorization-server

Every URL in the JSON (issuer, authorization_endpoint, token_endpoint, registration_endpoint) must start with https:// and your real public host. If they show http://, a LAN address, or the wrong host, that’s the problem:

  • Set your domain in the app. Under Settings → Domain & HTTPS, make sure the custom domain is filled in. As of 0.59.1, when a custom domain is configured CompassDocs advertises its OAuth endpoints over HTTPS at that domain regardless of what your proxy forwards — which fixes the most common case on its own.
  • Behind your own reverse proxy? If the metadata still shows http://, your proxy isn’t forwarding X-Forwarded-Proto: https. See Behind your own reverse proxy.
  • Reachability & TLS. The host must be reachable from the public internet over HTTPS with a valid (CA-signed) certificate. A self-signed cert, a LAN/VPN-only address, or localhost will fail — Claude’s servers dial the endpoint directly.
  • Public DNS, not just internal DNS. The hostname must resolve on the public internet. If your browser opens the site but Claude reports it can’t connect, check from outside your network: nslookup YOUR-HOST 8.8.8.8. An install that only exists in internal DNS (split-horizon) is invisible to Claude’s servers — see below.
  • “Your account was authorized, but the integration rejected the credentials it just issued.” Sign-in completed, but the follow-up MCP call — the only request that carries its credentials in an Authorization: Bearer header rather than the request body — bounced with a 401. Something between Claude and the app is intercepting that header or the call itself. The usual suspects: Cloudflare’s orange-cloud proxy (switch the record to DNS-only, or exempt /api/mcp and /api/oauth/* from WAF/bot rules), an IIS site with Windows or Basic authentication enabled (use Anonymous only), or a reverse proxy that clears the Authorization header. To confirm: a request with a personal API token against /api/mcp succeeds directly on the server but fails through the proxy.

The one-click connector runs from Anthropic’s servers, so it can only reach installs with a public DNS name. If your CompassDocs deliberately lives on internal DNS or behind a VPN, pick one of these:

Option A — expose the hostname publicly (recommended). Add a public DNS record for the same hostname, terminate TLS with a CA-signed certificate at your reverse proxy, and (if you want to stay locked down) restrict inbound traffic at the proxy or firewall. Users keep signing in exactly as before; the connector just becomes reachable.

Option B — a local bridge in Claude Desktop. Claude Desktop can run a local MCP process on each user’s machine, inside your network, where internal DNS works. Each user creates a personal token under your name → API tokens, then adds this to Claude Desktop’s MCP settings:

{
"mcpServers": {
"compassdocs": {
"command": "npx",
"args": [
"-y", "mcp-remote", "https://docs.internal.example.com/api/mcp",
"--header", "Authorization: Bearer YOUR-PERSONAL-TOKEN"
]
}
}
}

This works only in the desktop app (claude.ai on the web still connects from the cloud), needs per-machine setup, and the token acts with that user’s role — revocable anytime from the same API tokens page.