Documentation
IntegrationsFabric MCP Gateway

Fabric MCP Gateway

Use Fabric as a unified MCP server from Claude Desktop, Cursor, VS Code, and any MCP-compatible client. Access all your projects, documents, libraries, workflows, and connected tools through a single endpoint.

The Fabric MCP Gateway turns your entire Fabric instance into a single MCP server. Instead of configuring each tool separately in every AI client, you connect once to Fabric and get access to everything — your projects, documents, libraries, workflows, and all your connected MCP servers — through one URL.

Why Use the Gateway?

Without GatewayWith Gateway
Configure each MCP server separately in each clientOne URL in your client config
Manage API keys per tool per clientFabric manages all credentials centrally
OAuth flows broken in most clientsFabric handles OAuth + token refresh
No visibility across project artifactsFull access to projects, docs, libraries
Credentials scattered in config filesCredentials encrypted in Fabric, never leave the server
No usage controlsTime-limited, human-approved runtime authority

Quick Setup

Sign in from your coding agent

Connect from the project you want the agent to work on. The project has its own gateway URL, https://your-fabric.com/api/mcp-gateway/projects/<project-id>: add it to your tool with no key, then sign in from the tool. The first request is answered 401 with a WWW-Authenticate challenge naming that URL's sign-in metadata, the tool opens your browser, and you approve the tool once. You are never asked to choose an organization or a project: the URL already says which. The project's Connect your agent dialog shows the same entries with your deployment's URL and the project filled in.

Run it in the project's folder:

claude mcp add --scope local --transport http fabric-<end-of-project-id> https://your-fabric.com/api/mcp-gateway/projects/<project-id>

The server is named fabric- and the last six letters and digits of the project's id, the same name Codex and fabric instructions init use, so a server added from the dialog is the one init finds. A server you already named fabric that points at this project keeps working and is not duplicated. Then run /mcp in Claude Code and choose Authenticate.

Use Add to VS Code in the Connect dialog, or add the server to your MCP configuration with no headers. VS Code installs the server for every folder it opens, so the Connect dialog names it after the project and the end of its id (fabric-<project-name>-<id>), and two projects do not collide, even when they share a name:

{
  "servers": {
    "fabric-example-project-a1b2c3": {
      "type": "http",
      "url": "https://your-fabric.com/api/mcp-gateway/projects/<project-id>"
    }
  }
}

VS Code asks you to sign in the first time the server starts.

Use Add to Cursor in the Connect dialog, or add a server with only the project's URL, https://your-fabric.com/api/mcp-gateway/projects/<project-id>. Cursor installs it for every folder it opens, so the Connect dialog names it fabric-<project-name>-<id>, with the end of the project's id so two projects of one name stay apart. Cursor opens the browser to sign in.

Codex keeps one list of servers for every project on the machine, so the Connect dialog names this project's server fabric- and the last six letters and digits of its id (fabric-ewrite for project-checkout-rewrite), and fabric instructions init registers the same name. Two projects then stay apart in Codex's list:

codex mcp add fabric-<end-of-project-id> --url https://your-fabric.com/api/mcp-gateway/projects/<project-id>

The command opens your browser to sign in and finishes once you approve. If the sign-in did not finish, run codex mcp login fabric-<end-of-project-id>.

Any client that implements MCP authorization works from the server entry alone. It contains no credential, so a project can commit it as .mcp.json:

{
  "mcpServers": {
    "fabric": {
      "type": "http",
      "url": "https://your-fabric.com/api/mcp-gateway/projects/<project-id>"
    }
  }
}

What you approve is the same for every tool, and it is for that project alone: read the project, its features and bugs and their decisions and revisions, its documents, its context, and search its knowledge; read its coding instructions; and suggest changes to them, held for review and never published by the agent. The consent page names the project and its organization, and what you approve is exactly what the page showed: if the connection changes while the page is open, nothing is approved and the tool has to start the sign-in again. The agent works on that project and nothing else in Fabric: the gateway offers it the project's tools only, and no organization-wide tool and no connected server's. A token issued for one project works only at that project's URL, so it cannot be pointed at another project or at the organization-wide gateway. If you can no longer open the project, the agent's next request is refused.

The tool stays signed in until you revoke it under Account → Connected agents, which lists one row per project and organization grant and signs the tool out of it at its next request. To work on another project, connect from that project.

A client must send the project's URL as the resource of its authorization, as the MCP authorization specification requires. The sign-in metadata at /.well-known/oauth-protected-resource/api/mcp-gateway/projects/<project-id> names exactly that URL, and a project URL never falls back to an organization-wide sign-in.

The organization-wide gateway

Connections made before projects had their own URL, at https://your-fabric.com/api/mcp-gateway, keep working unchanged: they are signed in for one organization, which is chosen on the sign-in page when you belong to several, and reach all of its projects. The Connect dialog no longer offers it. A token issued for one project is refused there, and the refusal names the project's URL to use instead.

The sign-in page shows the organization it will use, and what you approve is exactly what the page showed: if the organization the server would use differs, nothing is approved and the tool has to start the sign-in again. mcp:read, the scope behind "Read this organization's projects and context", covers that organization's projects, features and bugs with their decisions and revisions, documents, project context, coding instructions, document libraries, workflows and frames, plus the list of connected servers. It does not cover your personal AI chats, and the identity tools list only the organization you signed in for. An OAuth sign-in never holds mcp:write, so it cannot call a connected server's tools unless that server declares them read-only.

Or use an API key (CI and headless)

Where nobody can approve a sign-in in a browser, authenticate with a key.

1. Create an API Key

Go to Settings → API Keys and create a new key. Copy the key — it starts with fab_.

For organization context, create the key from your organization settings page.

A new organization key starts with MCP Read only, so it can read and cannot change anything until you tick a write scope. MCP Write (mcp:write) grants every write tool, including workflows and pages. For an agent that should do one thing, tick the narrow scope instead, such as workflows:write, frames:write or features:write. Keys you created earlier keep the scopes they have.

2. Configure Your Client

Edit your claude_desktop_config.json:

{
  "mcpServers": {
    "fabric": {
      "url": "https://your-fabric.com/api/mcp-gateway",
      "headers": {
        "Authorization": "Bearer fab_xxxx_xxxxxxxxxx"
      }
    }
  }
}

Go to Settings → MCP Servers → Add Server:

  • Name: Fabric
  • URL: https://your-fabric.com/api/mcp-gateway
  • Headers: Authorization: Bearer fab_xxxx_xxxxxxxxxx

Add to your MCP configuration:

{
  "servers": {
    "fabric": {
      "url": "https://your-fabric.com/api/mcp-gateway",
      "headers": {
        "Authorization": "Bearer fab_xxxx_xxxxxxxxxx"
      }
    }
  }
}

Any MCP-compatible client can connect using the Streamable HTTP transport:

Endpoint: POST https://your-fabric.com/api/mcp-gateway
Auth:     Authorization: Bearer fab_xxxx_xxxxxxxxxx
Protocol: MCP 2025-03-26 (Streamable HTTP)

Health check: GET /api/mcp-gateway returns server info (no auth needed).

3. Organization Context (Optional)

A personal API key (fab_) belongs to you, not to an organization. If you belong to more than one, name the organization the connection should start in with the X-Organization-Id header:

{
  "headers": {
    "Authorization": "Bearer fab_xxxx_xxxxxxxxxx",
    "X-Organization-Id": "your-org-id"
  }
}

Fabric checks that you are a member of that organization and refuses the request otherwise. The header chooses where the connection starts. It does not confine the key: a personal key can still move between your organizations with fabric_switch_organization, and a browser session follows the organization you are working in. A connection that must stay in one organization uses an organization API key (org_) or an OAuth sign-in. Both are fixed to one organization when they are issued, ignore this header, and cannot switch.

Coding Instructions

A project's Coding Instructions tab publishes one version of its skills, agents, rules, and setup files, and serves them to a connected agent over the six tools below. The files come from one of two places: a folder uploaded in Fabric, or a branch of the project's repository that Fabric keeps in sync.

How the instructions and agent memory move between your repository, Fabric and the coding tool, and what each project can configure:

Loading diagram...

Connect a tool from the tab

Open the tab and choose Connect your agent, beside Fabric MCP in the status strip under the heading. The dialog has one tab for each of five tools, Claude Code, Codex, VS Code, Cursor and Other, and one action for each. You approve the connection once in your browser: there is no key to create or paste.

TabWhat you doWhat it sets up
Claude Code and CodexChoose where the repository is, copy the one line shown and run it (see below)The Fabric CLI your deployment serves, run straight from its URL, so nothing is installed first. It signs in through your browser and, by default, installs the project's instructions as a plugin for that tool, with no clone (see Instructions as a plugin)
VS Code and CursorChoose Add to VS Code or Add to CursorThe gateway as an MCP server. There is no hook; the agent compares its checkout with the published version at each session start
OtherCopy the server entry (it holds no credential)Any MCP client that supports sign-in asks you to approve it the first time it connects

The setup line. For Claude Code and Codex the dialog asks Where's the repository? and shows one line per answer, with <tool> the tab you are on (claude-code or codex) and <tgz> your deployment's tarball, https://your-fabric.com/cli/fabric-<version>-<build>.tgz. You need Node.js 22 or later and nothing else: npx comes with it.

  • No clone (recommended). npx -y <tgz> instructions init --project <id> --tool <tool> --plugin. Run it in the folder your agent works in, usually your product's own checkout. Nothing is cloned: the instructions arrive as a plugin built from what the project publishes, and the project's memory folders are mirrored as plain files. A plain init does the same, unless you pass --clone or run it inside a clone of the instructions' repository.
  • Already cloned. npx -y <tgz> instructions init --tool <tool>. Run it in the top folder of your clone of the project's repository, or, when the project's instructions live in a folder of that repository, in that folder (<rootPath>/ inside the clone). Not in any other folder: the CLI refuses and says where to go. It finds the project from the checkout's git remote.
  • Clone it for me. One command, npx -y <tgz> instructions init --project <id> --tool <tool> --clone <dir>. It makes <dir> (a folder that does not exist yet, or is empty), clones the project's repository into it with your own git credentials, and finishes setting up inside it, in the project's own folder when the instructions live in a subfolder. Open your coding tool in that folder afterwards.
  • An upload project has no repository to find it from, so its line names the project: npx -y <tgz> instructions init --project <id> --tool <tool>. Run it in the folder your agent works in.

Each is one command with no && and no cd, so it runs in Windows PowerShell 5.1 as well as bash. The dialog adds --base-url https://your-fabric.com, the address you are on, unless the CLI was built for exactly that address (see below), so the line works on any deployment with nothing configured. After it runs, the CLI opens your browser to approve the connection once. Run by an agent with no terminal, it prints the URL for you to open and waits up to five minutes for you to finish. Under CI it starts no browser sign-in at all: it stops and names the sign-in command, so a CI run signs in with an API key (below).

Your checkout uses your own git credentials; Fabric never hands out repository credentials. If git cannot sign in to the repository yet, the dialog's Git can't sign in to the repository section shows how to sign git in for the provider: gh auth login for GitHub, glab auth login for GitLab, and for Azure DevOps one git ls-remote of the repository, which Git Credential Manager signs in the first time.

The CLI is the one built from your deployment's own source, listed with its version, its integrity hash, the oldest version the deployment accepts and the address it was built for at /.well-known/fabric-cli.json. The tarball's name carries the build, ten hex digits of the CLI's own hash: the version changes only on a release, npx keeps running whatever it first fetched from a URL, and a build that changed has to be at a URL it has not seen. A name from an older deployment is answered with a redirect to the current one. Baking the address in is optional: a build that knows where it will be served (FABRIC_CLI_ORIGIN, NEXT_PUBLIC_SITE_URL or APP_URL set when it is built) records it, and a build that does not, such as a preview or staging deployment whose address is not known until it runs, records none. Either way --base-url wins over what is baked in, so a CLI built for another address is harmless. A deployment that serves no CLI says so in the dialog and leaves the MCP entries. The package on the npm registry is not a way in: its release predates --base-url.

For CI and headless machines, the dialog's CI or headless? Use an API key section mints a key that carries mcp:read, instructions:read and instructions:write and expires after 90 days. It can read the instructions and suggest a change, but it cannot publish one.

Instructions as a plugin

With No clone, the project's coding instructions reach your coding tool as a plugin that Fabric builds from the published version. No one clones the instructions' repository, and the next session picks up whatever the project published last.

From the instructionsIn the plugin
skills/<name>/SKILL.md (and the rest of skills/<name>/)Skills, named fabric-<id>:<name>
agents/<name>.mdAgents
commands/**Commands
CLAUDE.md, else AGENTS.mdHanded to every session as context when it starts
(added by Fabric)The project's MCP server (named fabric in Claude Code), fabric-instruction-access for finding and reading instruction files, and fabric-living-memory for specs and notes

Standard layout. Keep the instructions in these folders, at the root of the instructions or under .claude/ (.claude/skills/<name>/SKILL.md works the same as skills/<name>/SKILL.md; folder names are matched without regard to case):

PathWhat it is
skills/<name>/SKILL.mdA skill: a folder per skill
agents/<name>.mdAn agent: one markdown file directly in agents/
commands/**Commands
rules/**/*.mdProject rules. Fabric delivers them automatically into .claude/rules/fabric-<id>/ for Claude Code and AGENTS.override.md for Codex, and keeps passive reference copies in the plugin
CLAUDE.md or AGENTS.mdThe memory file every session starts with

Rules. Claude Code loads the markdown files of .claude/rules/ in your project. A rule without paths: frontmatter loads at the start of every session like CLAUDE.md; a rule with paths: loads when Claude works on a matching file. Fabric copies each rule byte for byte, frontmatter included, into .claude/rules/fabric-<id>/ at the start of every session, and when you run the setup, so the first session already has them. Rules you add or edit in .claude/rules/ yourself are never touched. A file in that folder that you edit is kept, and Fabric stops updating it. Codex has no rules folder, so the rules are added after the memory file in AGENTS.override.md, each under its own heading; a rule with paths: is marked as applying when working on those files. Both are limited (64 files and 256 KiB for Claude Code, about 24,000 characters for Codex); the setup says when rules were left out of automatic delivery. The plugin keeps the rule text as passive reference files, indexed by original path in the fabric-instruction-access catalog. The skill directs the agent to inspect rule scopes and read every unscoped rule and every matching scoped rule before affected work, including files beyond automatic delivery limits.

Read referenced files on demand. Every session receives a pointer to the generated fabric-instruction-access skill, even when there is no root CLAUDE.md or AGENTS.md. Its catalog.json lists all instruction paths and available local copies. Search relevant entries instead of loading the full catalog into context. Files outside plugin folders, such as standalone scripts, settings and knowledge files, remain listed. The agent uses fabric_list_project_instructions to find paths and fabric_get_project_instruction to read their original text through the project's authorized Fabric MCP connection. For example, @MAIN.md in the instructions' root CLAUDE.md refers to that instruction tree's MAIN.md, even when the project checkout has a different file with the same name.

The skill explains how to retain the repository generation and commit across list and text pages, and how to detect changes to an uploaded publication. It directs the agent to read each relevant file until nextOffset is null. Access denials, missing files, binary files and size refusals remain explicit limits. Reading a script does not execute it or materialize its dependencies; a workflow requiring local execution needs an authorized checkout. The Coding Instructions tab and CLI still report which files lack a native plugin slot.

After the sign-in, the dialog has one more step for the tool you picked.

Claude Code: Turn on the plugin in Claude Code. The setup registers the plugin for the folder and then asks you to approve the plugin's command once. Claude Code shows the exact command and takes the answer only in your own terminal, never from inside a coding session. If the setup could not ask you, the dialog shows the command to run in the folder:

claude plugin install fabric-<id>@fabric-<id> --scope local

<id> is the last eight letters and digits of the project's id, and fabric-<id> is the plugin's name. Then start a new session. To let the agent call Fabric's tools too, run /mcp in Claude Code, pick the server named plugin:fabric-<id>:fabric (the plugin's MCP server is named fabric, and Claude Code lists it with the built-in servers because the plugin brings it) and choose Authenticate. Your browser opens so you can approve it once. The instructions and the memory folders do not need this sign-in, because the setup's own sign-in covers them. A plugin set up before the server was named fabric listed it as plugin:fabric-<id>:fabric-<id>; once its CLI copy updates, /mcp shows plugin:fabric-<id>:fabric as Needs authentication, so choose Authenticate once more.

Codex: Turn on the plugin in Codex. The setup renders the plugin into ~/.codex/plugins/fabric-<id>, lists it in your personal marketplace (~/.agents/plugins/marketplace.json) and installs it in Codex itself. Codex keeps its own copy of an installed plugin, so at each session start the hook installs it again whenever that copy is older than what the project publishes; Codex loads the new copy from the next session. If the install did not work, the dialog shows the command to run:

codex plugin add fabric-<id>@personal

personal is the name of the marketplace file; if yours is named differently, the setup prints the line with your name. Trust the project hook once with /hooks. Codex has no slot for an always-on file, so the setup also writes AGENTS.override.md in the folder, kept out of your commits: your own AGENTS.md first, then the project's instructions. In Codex the plugin's MCP server keeps the name fabric-<id>, because every project's Codex plugin shares one personal marketplace.

One plugin, one project. A plugin belongs to one project on one deployment. Its name comes from the last eight letters and digits of the project's id, and its description names the project and the deployment it was built for. If a name is already taken by another project (or by the same project on another deployment), the setup refuses and says which one holds it, instead of repointing the folders already set up for that one. Remove the other setup's plugin and folder first, then run the setup again.

To set a folder up the clone way instead (a checkout of the instructions and a session hook), pass --no-plugin.

Save specs and notes to the repository

While they work, agents write specs, task breakdowns and notes. With write folders, those files reach the project's repository through Fabric and come back as Living Memory for the next agent, without anyone cloning that repository or running git.

  1. A project admin names the folders once. In the Context tab, open the menu beside Sync now in the Living Memory section and choose Write folders (see Write folders). Each folder lands its files as a pull request (the default) or, if an admin turns it on, as a direct commit. A folder is also either Index for AI search (the default) or Store only. Store only keeps its files in Living Memory and readable by agents, but out of AI search, keyword search and summaries: pick it for a folder that will hold thousands of task files, so they do not crowd out everything else. In the project's Context tab, a Store only folder's files show as Ready with a "Store only" label and are not counted among the sources still processing. fabric_memory_targets reports each folder's indexMode.
  2. Each developer runs the setup line once (No clone). It mirrors the write folders into the folder as plain files at their repository paths, such as docs/ai/, kept out of your own commits.
  3. Agents write ordinary files there. The fabric-living-memory skill tells the agent which folders to use.

From then on it runs by itself:

WhenWhat happens
A session startsThe folders' current files are brought in, so the agent sees what others wrote
A Claude Code turn endsNew, changed and deleted files are sent. Fabric commits them, or opens a pull request, with the repository connection's own credential
CodexCodex has no end-of-turn hook, so files are sent when the next session starts
A few seconds laterThe next sync reads committed files into Living Memory. A file in an open pull request joins Living Memory once someone merges it

On a Push directly folder, a write that loses a race with another write that reached the branch first is retried on the new branch tip. Only a branch that refuses the push (branch protection, a server hook, or missing write permission) turns the write into a pull request, with reason protected.

Tell agents where to write in your instructions. A file lands at the same path in the repository that it has in your folder: docs/ai/specs/login/spec.md here becomes docs/ai/specs/login/spec.md there. Skills often hard-code where they save their output: make that path a write folder, or add a line to your instructions such as Save specs to docs/ai/specs/<feature>/spec.md. A file outside every write folder stays on your machine.

What a write folder takes. Text files ending in .md, .markdown, .txt, .json, .yaml or .yml, up to 2 MiB each. Other files, larger ones and links are reported and not sent, and nothing whose name starts with a dot (a file such as .draft.md, or anything in a folder such as .notes/) is sent. A path your own repository tracks with git is left to git. A change of more than fifty files is sent as several writes.

Nothing you changed is overwritten. If someone else changed a file since you last received it, your change is not written and the file stays as you left it. The CLI reports the conflict, and you choose: fabric memory pull --accept-remote <path> takes their version (or, if they deleted the file, removes yours), and fabric memory status --clear dismisses the report. Here fabric is the CLI the way the setup line runs it, from the folder you set up: npx -y <tgz> memory status, plus the setup line's --base-url if it had one.

Check that a file arrived. fabric memory status reports pull requests with their links, and conflicts, refusals and changes not sent yet. An agent can ask too: the id of each write the session hook sent is in .fabric/memory.lock (in its outbox), and fabric_memory_write_status reads its outcome. fabric_memory_targets lists the folders, their branch and the commit the last sync read.

Resume a work item. Keep one work item's specs and tasks together in docs/ai/specs/<work-item-id>/, inside a write folder. To pick it up, an agent lists that folder with fabric_memory_read (prefix), then reads a file by its path, a page at a time for a large one. This needs no write scope: a coding tool's default sign-in can do it, and it works for Store only folders too. The same files are on disk in your project folder at the same paths when the setup line has been run, so the agent can also read them there. The plugin's fabric-living-memory skill tells the agent so.

The agent cannot write through Fabric's tools on its own. fabric_memory_write needs memory:write, a scope that a coding tool's sign-in never carries, so an agent's files reach the repository through the folder and the hooks above. See Living Memory writes for the tools and the scope.

Example: a password reset feature, end to end

A team keeps its coding instructions in Fabric and wants every spec an agent writes to land in the repository, where the next agent (and Fabric's own AI features) will read it. The steps below follow one feature from start to finish with Claude Code.

  1. An admin chooses where specs go, once. In the project's Context tab, open the menu beside Sync now in the Living Memory section, choose Write folders, then Add a write folder: docs/ai, landing as Pull request (or Push directly to skip review).
  2. The team says where specs belong, once. In the project's coding instructions, the CLAUDE.md gets a line such as Save specs to docs/ai/specs/<feature>/spec.md and task lists to docs/ai/specs/<feature>/tasks.md. Every session receives it from the plugin.
  3. Each developer sets up their machine, once. In the Coding Instructions tab, choose Connect your agent, then Claude Code and No clone (recommended). Run the line it shows in the product's own checkout, approve the sign-in in the browser, then confirm the plugin in the terminal (step Turn on the plugin in Claude Code). Start a new session.
  4. A developer asks for the spec. In Claude Code: Write a spec for password reset. At session start the team's skills and rules came from the plugin and the specs teammates already wrote were brought into docs/ai/. The agent writes docs/ai/specs/password-reset/spec.md. When its turn ends, the hook sends the file and Fabric opens a pull request with it (or, with Push directly, commits it to the branch).
  5. The spec becomes team memory. Once the pull request is merged (or straight after a direct commit), the next sync reads the file into Living Memory. Any agent connected to the project can now find it, and Fabric's AI features use it.
  6. A teammate picks it up. On another machine, the next session brings docs/ai/specs/password-reset/spec.md in by itself, and an agent without the local files can list docs/ai/specs/password-reset/ and read the spec with fabric_memory_read. If both people edit it before either has the other's change, nothing is overwritten: the CLI reports the conflict, and fabric memory pull --accept-remote docs/ai/specs/password-reset/spec.md takes the committed version. To keep your own changes, copy them aside first, take the committed version, then make your changes on top of it: the next turn sends them.

With Codex the steps are the same, except that the setup also installs the plugin in Codex (step Turn on the plugin in Codex), and files are sent when the next session starts.

What an agent can do

ToolWhat it does
fabric_list_project_instructionsBrowse or search the published files, or ask what changed since a sinceDigest
fabric_get_project_instructionRead one published file by path, paged for large files
fabric_get_project_instruction_bundleInstall the whole published tree as one zip, and report what changed since a sinceDigest
fabric_instruction_checksReport whether the session is set up the way the instructions expect: the credential's scope, project access, the published version, whether the installed copy is current, and the environment variables and tools the project declares. Every suggested fix is advice for the developer, not authority to change anything
fabric_propose_project_instruction_changeSuggest an edit (a file's whole new content, or a deletion). It opens a proposal for someone who can edit the instructions to approve; it changes nothing the project reads
fabric_add_instruction_lessonRecord a lesson, a mistake the team should not repeat, as a new file under Lessons/, through the same proposal path

The two writing tools are held for review: the agent reports a suggestion as awaiting review, never as applied. Only a person with permission to edit coding instructions publishes anything.

Project readers can propose adding, editing, or deleting a file from the Coding Instructions tab. Proposals pass the same validation and secret scanning as uploads before an instruction editor can review their changes and approve publication. Rejecting a proposal leaves the published files unchanged. If the published version changes before approval, submit the proposal again against the current version. You can cancel your own proposals once validation is no longer running. Each project allows up to 25 active proposals, with a limit of five per proposer. Large file bodies may be omitted from the review preview; editors can open a paged view of the full text. Canceled uploads can continue to count toward the limit until their upload links expire and cleanup finishes. On a project whose instructions come from a repository, the files are changed in git. A suggestion from the tab or from an agent becomes a commit on the proposer's own branch there, with one pull request collecting each person's changes, and it is reviewed and merged in the repository. A merged pull request syncs on its own.

Only published versions are available through MCP and local sync. A pending proposal doesn't change the files your connected agents receive.

Work on a repository project from the tab

On a project whose instructions come from a repository, the tab works the way git does: the branch is the history, and Fabric's copy follows it.

  • Commit. Someone who can edit coding instructions presses Edit on a file, writes a commit message, and chooses Commit to the branch. The message starts as Update <file>; Add file, Rename and Delete file start from Add <path>, Rename <old> to <new> and Delete <path>, and a rename is one commit that git reads as a rename. Fabric runs the secret scan an upload gets before anything is pushed, and a change it refuses is not committed, with its findings on the page. The commit names you as author, with a Fabric no-reply address, and Fabric as committer. Fabric's copy takes the commit a few seconds later, from a sync of the branch's real files, and the status block says so until it has.
  • Suggest as a pull request. The alternative to committing, and the only choice for a reader once the project lets read-only members propose. If the branch is protected, or keeps moving, Fabric opens the pull request for you and links it. If a teammate changed the same file since you started, nothing is written: you choose between retrying the commit, suggesting it as a pull request and cancelling, and what you typed stays.
  • Commits. The button that is History on an upload project reads Commits here: the branch's own history within the synced folder, newest first, 30 at a time. Each row has the short commit (a link to GitHub, GitLab or Azure DevOps), its author, its age and its subject, and is marked Published when Fabric's copy is of it, Refused by scan when the secret scan refused its files, or Not synced yet when it is newer than the published commit and Fabric has not taken it. A commit message that looks like it contains a secret is shown as withheld. Nothing in Commits publishes, rolls back to or deletes a version: Fabric's copy follows the branch.
  • Revert. Undoes a commit with a new commit on the branch, as git revert does. It is refused, with the reason, when a later commit changed the same files, when a file it would restore looks like it contains a credential, for a merge commit or a repository's first commit, and on a protected branch, where you revert in the repository instead.
  • Compare with parent. Shows what a commit changed within the synced folder: the files added, removed and changed, and a line diff of each changed file once you open it. A file Fabric will not show (it is in a commit the secret scan refused, it holds a secret, it is not text, or it is too large) is described in one line instead of a diff. Comparing needs the same right as committing; everyone who can read the tab sees the commits themselves.

A project in Read-only mode makes no commit and no revert from Fabric, whatever the member's role, and says so; suggesting and reading are unchanged.

Move uploaded instructions into a repository

An upload project can hand its published files to a repository without anyone copying them. Settings offers Move to a repository… to a member who can create and update coding instructions, once something is published and a repository is connected to the project.

  • Start. Choose the repository, the branch and a folder. The folder must not hold any files yet, and a new folder is fine; leave it empty to put the files at the repository root, as long as they would not overwrite anything there. Fabric opens one pull request carrying the published files. It refuses, with the reason, a folder that already has files, a project that already has a repository sync set up, and a project with nothing published.
  • While it is open. The status under the summary follows the pull request: Preparing the pull request… while it is opened, then the repository, the branch and the pull request awaiting its merge, with a link to it. The instructions stay as published until it merges. Uploads, edits, publishing, ignore rules, repository settings, reverts and manual syncs are paused, and each says why: Moving to the repository: pull request #n is open. Everyone who reads the tab sees the status; Cancel move is for members who can create and update.
  • If it is blocked. The status gives the reason in a sentence and offers Retry when a retry can help. A failure no retry can fix says to cancel the move and start it again. If the project was switched to the repository by something other than the move, Cancel move and Retry are refused and the status says so: the only way out is Switch to upload mode in Settings.
  • When it merges. The status reads Merged — switching the project to the repository… until the first sync from the repository has succeeded. The repository is then the source of truth and the tab works as on any repository project. If the pull request is closed without merging, the move ends, the instructions stay as published, and the tab says so once. A pull request that was merged into a different branch than the one the project reads ends the move the same way: Fabric does not sync it, and the status says it was merged into another branch.
  • If the first sync cannot finish. While the project is switching over, Switch to upload mode in Settings ends the move and gives the tab back its uploads. It is offered only while a move is switching over or blocked, and nowhere else a move is open; whatever was already merged in the repository stays there.
  • Cancel. Cancel move closes the pull request without merging it and gives the tab its controls back. A pull request that has already merged cannot be canceled: its files are in the repository and the project is switching to them.

Keep a checkout current

This applies to Already cloned and Clone it for me; with No clone the plugin already follows the published version. The session-start hook asks, every time a Claude Code or Codex session starts, whether the published version moved, and tells the agent when it did.

  • A project that syncs from a repository. The hook fast-forwards the branch the project follows to its newest commit when your checkout is clean and on that branch. It is a fast-forward and nothing else: it never merges, rebases, resets or stashes, and when it cannot (uncommitted changes, another branch, a detached HEAD, a diverged history, a shallow clone) it leaves the checkout exactly as it was and prints one line saying why. init --report-only writes a hook that only reports and never fetches.
  • An upload project. The hook reports when the published instructions changed; it applies nothing unless init was given --apply.

Codex asks whether to trust the folder the first time it opens it. Trust it, then run /hooks once to trust the project hook. VS Code and Cursor have no hook, so the agent makes the comparison through fabric_instruction_checks at the start of a session. An agent connected over MCP only reports: it never pulls, and the pull itself stays with you.

What No clone leaves on your machine. None of it is in your repository's history:

  • In the folder, for Claude Code: .claude/settings.local.json, which turns the plugin on, names the marketplace it comes from, and holds SessionStart hooks that run instructions rules and memory pull, and a Stop hook that runs memory push. Also for Claude Code: the project's rules in .claude/rules/fabric-<id>/, with a .fabric-managed.json that records what Fabric wrote there. For Codex: .codex/hooks.json and AGENTS.override.md (the memory file and the rules). For both: .fabric/, which records the project and what the mirror last agreed with Fabric, and the mirrored write folders. The setup keeps all of these out of your commits, adding to the repository's own .git/info/exclude whatever git does not already ignore.
  • In the CLI's config folder (below): the CLI's own copy, the plugin's marketplace under cache/marketplaces/, and the built plugins under cache/plugins/. For Codex, the plugin in ~/.codex/plugins/ and its entry in ~/.agents/plugins/marketplace.json.

To undo it, run claude plugin uninstall fabric-<id>@fabric-<id> --scope local in the folder (or remove the plugin in Codex), then delete the hook entries, .fabric/, the mirrored folders and the rules folder .claude/rules/fabric-<id>/ (keep any file in it you edited and want). For Codex, delete AGENTS.override.md if you did not write it yourself. Files already sent stay in the repository.

What Already cloned and Clone it for me leave, and how to check it and undo it. Two things, and neither is in your repository's history:

  • A hook entry in the checkout: .claude/settings.local.json for Claude Code, .codex/hooks.json for Codex. init adds both files to the repository's own .git/info/exclude. The entry is a SessionStart command that starts with node, then the CLI's own copy, then instructions check (or sync) with your project and your deployment.
  • That copy of the CLI, one file per deployment: cli/<deployment>/fabric.mjs inside the CLI's config folder (%APPDATA%\fabricai-nodejs\Config on Windows, ~/.config/fabricai-nodejs on Linux, ~/Library/Preferences/fabricai-nodejs on macOS). It is why the hook works with no fabric command installed. Each run of the setup line replaces it, and the copy also keeps itself current (below). A small update-check.json beside it records when it last asked.

The copy updates itself. Once a day, at the end of a session-start hook run and after the hook has printed what it has to say, the copy asks the deployment the hook is bound to which CLI it serves now. When that is a different build from the one running, the copy downloads it from that deployment, checks it against the integrity hash the deployment publishes, and replaces itself. The new copy runs from the next session. Only that deployment is ever asked (over https, or plain http to localhost for a deployment you run yourself), nothing downloaded is run, and only the copy and its update-check.json are written, inside the CLI's config folder. It only runs when at least five seconds of the hook's ten-second limit are still unspent, and any failure (no network, a hash that does not match, a copy another session holds open) leaves the earlier copy as it was, prints at most one line on stderr and never touches the hook's own output. To turn it off, set FABRIC_CLI_NO_SELF_UPDATE=1; it is also off whenever CI is set. Run the setup line again to update by hand.

When a message from the CLI tells you to run a command, it gives the short npx line for the deployment, even from the copy the hook runs. That line keeps working after the deployment moves on, because a tarball name it served earlier answers with a redirect to the current one.

To check it, run the setup line's CLI with instructions doctor --project <id>: it reads the hook entry, says whether it is in the form this CLI would write, and warns when the file it runs is gone. To undo it, delete the project's instructions check or instructions sync entry from the hook file (and its lesson-prompt entry, if you set up lesson capture), and delete the deployment's folder under cli/ if no other checkout uses it. auth logout removes the saved sign-in.

The tab shows the published side. For a repository project, a status block under the summary states which version, commit and branch are published, whether Fabric's copy is current or was held back because a commit was refused by the secret scan (with a link to the findings), and whether automatic sync is on. Your own checkout is not tracked there: the hook in your coding tool is what tells you when it is behind.

A connected agent finds them on its own. Every project fabric_get_project and fabric_list_projects return carries a codingInstructions field: { "published": false } when there is nothing to load, and the snapshot's version, fileCount, digest and publishedAt when there is. The connection handshake tells the agent what to do with it: call fabric_get_project_instruction_bundle to install the whole approved tree in one step, or fabric_list_project_instructions and fabric_get_project_instruction to read individual files, and follow them while working on that project. The field is omitted entirely for a key that does not hold the instructions:read scope (or a coarse mcp:read/mcp:write).

Keeping an installed copy current does not always mean downloading it again. Pass the digest you last installed as sinceDigest to either fabric_get_project_instruction_bundle or fabric_list_project_instructions:

  • If the digest still matches, you get "unchanged": true and nothing else: no file list, no manifest, and no zip URL, so nothing is built or transferred. This is the only case that short-circuits.
  • If it has moved on, you get the response you would have got anyway, in full, plus changes (the added, removed and changed paths) and since, the snapshot that digest names. sinceDigest tells you what changed; it does not send you a smaller download.
  • If Fabric has never published that digest for this project, or has since pruned it, you get "changes": null alongside the same full response. Treat it as a fresh install.

You do not need to tell the agent any of this: the connection handshake already carries it. To point an agent at one specific project in a chat, name the project and ask it to load that project's coding instructions.

Bootstrap a Project

A new project's Context tab is often empty, which leaves Fabric's AI features little to work from. A connected coding agent can fill it from the repository you already have open: it sets the project's description, then pushes your README and key docs as knowledge sources. The connection handshake tells the agent to offer this when a project's fabric_list_project_contexts comes back with few or no sources.

The flow uses two tools. fabric_update_project sets the description, and fabric_upsert_project_context pushes one file per call, keyed by the file's path in the repository:

{ "name": "fabric_update_project",
  "arguments": { "projectId": "proj_example", "description": "Billing service: invoicing, payment retries and dunning." } }

{ "name": "fabric_upsert_project_context",
  "arguments": { "projectId": "proj_example", "sourcePath": "README.md", "content": "# Billing service\n..." } }

{ "name": "fabric_upsert_project_context",
  "arguments": { "projectId": "proj_example", "sourcePath": "docs/architecture.md", "content": "# Architecture\n..." } }

Pushed files appear in the project's Context tab under Living Memory, grouped by the folder of their path.

Pushing the same path again with the same content answers unchanged and writes nothing, and content identical to a source already in the project (another pushed file, or a file, link or note added in the Context tab) answers duplicate. To replace a file that is already there, the agent passes the contentHash it read from fabric_get_project_context or fabric_list_project_contexts as expectedContentHash; if someone else has changed the file since, the push answers conflict with the current hash and who changed it, and nothing is overwritten. If the file was deleted since, the push answers conflict with current set to null; call again without expectedContentHash to recreate it, which answers duplicate instead if that content already exists elsewhere in the project. When a file was renamed or moved without changing, push it at its new path with the old path as movedFromSourcePath and the old path's contentHash as expectedContentHash: the stored source is renamed in place and answers moved, keeping its history, instead of leaving a second copy behind.

Coding-instruction files (CLAUDE.md, AGENTS.md, anything under .claude/, and skills, agents, hooks, rules and scripts) do not go through this flow. The agent proposes those with fabric_propose_project_instruction_change, which opens a proposal on the Coding Instructions tab for a person to review. The agent should also leave out secrets, .env files and generated output.

Pushing context needs a key with the projects:write or mcp:write scope (the key that Connect your agent mints cannot do it) and, as with every key, your own permission to add context sources to that project. If those docs already sit together in one folder, the Fabric CLI can push the whole folder instead: fabric context push <dir> --project <id> sends each text file by its path with the same unchanged, duplicate and conflict answers, and remembers what it sent so that later runs send only what changed. It needs the same projects:write scope. To start the agent flow, paste a sentence like this into your agent:

Use the Fabric MCP server to bootstrap the context for the project "Your Project" from this
repository: set its description and push the README and key docs, and tell me what you pushed.

What Tools Are Available?

When your client connects, it receives two categories of tools:

Platform Tools (Always Available)

These give the AI direct access to your Fabric data — no extra setup needed:

ToolDescription
fabric_get_identitySee your user context, active organization, and available orgs
fabric_list_organizationsList all organizations you belong to
fabric_switch_organizationSwitch between personal and org context
fabric_list_projectsList your projects with filtering and search, each with its published codingInstructions
fabric_get_projectGet full project details, including its published codingInstructions
fabric_create_projectCreate a new project
fabric_update_projectUpdate project name or description
fabric_search_project_knowledgeSearch feature descriptions, document contents, and available project source text with ranked excerpts
fabric_list_documentsList documents in a project (PRDs, specs, etc.)
fabric_get_documentGet full document content in markdown
fabric_list_project_contextsList a project's Context tab sources — uploads, meeting transcripts, crawled links, notes
fabric_get_project_contextRead one context source in full: transcript text, extracted file text, or crawled markdown
fabric_upsert_project_contextPush a text file into a project's Context by its relative path: unchanged content is skipped, changed content replaces the stored version and is re-indexed, and replacing a file requires the contentHash you last read so nobody's edit is silently overwritten
fabric_list_project_instructionsBrowse or search a project's published coding-instruction files, or ask what changed since a sinceDigest
fabric_get_project_instructionRead one published coding-instruction file by path, paged for large files
fabric_get_project_instruction_bundleInstall the whole published tree as one zip, and report what changed since a sinceDigest
fabric_instruction_checksCheck that this session is set up the way the project's coding instructions expect: scope, access, published version, whether your installed copy is current, and the variables and tools the project declares
fabric_propose_project_instruction_changeSuggest an edit to the published coding instructions; held for review, never published by the agent
fabric_add_instruction_lessonRecord a lesson as a new file under Lessons/, through the same review-gated proposal path
fabric_memory_targetsList a project's Living Memory write folders and where their files land
fabric_memory_readList the files under a Living Memory write folder, or read one file's text a page at a time; works with a coding tool's default sign-in
fabric_memory_writeWrite or delete plain files in a Living Memory write folder as one commit or pull request; needs the memory:write scope
fabric_memory_write_statusRead the receipt of a Living Memory write
fabric_list_workspacesList your document libraries (the Libraries page). The tool keeps its name for existing clients
fabric_get_workspaceGet a document library's details and document list
fabric_query_workspaceSemantic search (RAG) across a document library's documents
fabric_list_framesList your frames; with surface: "workspace" the organization's Workspaces you can open, with surface: "artifact" and a projectId a project's Artifacts
fabric_get_frameRead a frame's blocks, surface and runtime tools; outline:true returns block sizes without content for partial editing
fabric_create_frameCreate a page. Pass the whole page in blocks, a surface (artifact or workspace), and the tools its script calls in runtimeTools. A Workspace is shared with the organization unless sharedWithOrganization is false; any other page is private to its creator. shareOnCreate: true also makes a public link, where the organization allows public links. Asks the person in chat first when runtimeTools is set
fabric_share_frameChange who can open a page you own. scope is required: PUBLIC (a link anyone can open, only where the organization allows public links), WORKSPACE_AND_EMAILS, EMAILS_ONLY or PRIVATE. Asks the person in chat first (frames:write)
fabric_edit_frame_blockEdit part of a page block: read an outline, read the needed source window, then submit literal replacements with expectedUpdatedAt
fabric_update_frameAdd, remove or reorder blocks, or rewrite a page you created; with no frameId it changes the Workspace the user has open. Asks the person in chat first when it sets runtimeTools
fabric_list_workflowsList your automation workflows, optionally only the scheduled ones
fabric_get_workflowGet workflow details: schedule, project, nodes, edges and the latest run
fabric_list_workflow_runsList a workflow's recent runs, with the page each one published
fabric_get_workflow_executionCheck workflow execution status
fabric_execute_workflowStart a published workflow now, including a scheduled one (workflows:run)
fabric_create_workflowCreate a draft workflow from a graph, or from a preset that runs an agent on a schedule and publishes a page. dryRun returns the draft without writing (workflows:write)
fabric_update_workflowEdit a workflow's graph, or the fields of a preset (workflows:write)
fabric_publish_workflowPublish a workflow as a new version and put it on its schedule (workflows:write)
fabric_unpublish_workflowTake a workflow back to draft and stop its schedule (workflows:write)
fabric_pause_workflow / fabric_resume_workflowStop and restart a published workflow's schedule (workflows:write)

Writes need an API key with the workflows:write scope; a signed-in coding agent (OAuth) stays read-only. Each write is checked against what the key's owner may do now, so a scope never grants more than the role behind it. | fabric_list_chats | List recent AI conversations | | fabric_list_connected_servers | See all your connected MCP servers |

Search project knowledge

Call fabric_search_project_knowledge with an explicit projectId and a nonempty query to find a literal, case-insensitive keyword or phrase across feature (including bug) titles and descriptions, authored document titles and contents, and available project context text. Crawled URL pages and captured channel conversations participate; repository code-index contexts and sources without readable text are excluded. Feature rich-text descriptions are searched as text nodes rather than editor attributes. Search performs no model or embedding calls.

The tool requires both projects:read and features:read, or an existing mcp:read, mcp:write, or wildcard umbrella. Every call checks the creator's current project access. Organization keys and OAuth credentials remain bound to the organization that issued them; invited guests using browser or personal-key credentials read the project's hosting organization.

Exact titles or feature identifiers rank first (3), title substrings next (2), and body matches last (1). Ties sort by source kind, then ID. Each result provides its ID, source kind, bounded title and match-centered excerpt, excerptField (body, title, or identifier), truncation flags, and a readTool with readArguments for reading the source in full. Child page and conversation matches also include their parent contextId and pageId or bundleId. An unusually long source URL is omitted with sourceUrlOmitted: true; the ID-based read remains available.

limit defaults to 20 and accepts 1–50 results. maxBytes defaults to 12000 and accepts 8192–50000 UTF-8 bytes of the complete serialized JSON response text, including pagination metadata. Results are complete records from the ranked prefix; the response never cuts JSON. returnedCount, hasMore, and omissionReason distinguish a complete response from a page stopped by result_limit or response_budget. The tool reports exclusions rather than presenting unavailable source text as an empty search match.

When hasMore is true, pass nextCursor with the same project and query to continue. You may change limit or maxBytes. Cursors bind to the project, query, and hosting organization and resume after the last emitted record, so a record omitted for the byte budget remains eligible on the next page. This is live keyset pagination, not a snapshot: edits between calls can change ranks or matches. Restart the search when you need to include changed material.

Connected Server Tools (Require Authority)

Every MCP server you've connected in Settings → MCP Servers becomes available, namespaced by server name:

linear__list_issues       → List issues from your Linear connection
linear__create_issue      → Create an issue in Linear
github__list_repos        → List repos from your GitHub connection
slack__send_message       → Send a message via your Slack connection
notion__search            → Search your Notion workspace
fizzy__get_cards          → Get cards from Fizzy boards

A connected server's tools are held to the credential's scopes and, for any tool that may change something, to runtime authority. A tool counts as a read only when its server declares readOnlyHint: true; for an OAuth sign-in or an organization API key nothing else makes it a read, whatever its name. Everything else needs the mcp:write scope (an OAuth sign-in can never hold it, so it cannot call those tools) and a runtime grant. Your own session and your personal API key keep the name-based guess (get_, list_ and the like) for deciding whether a grant is asked for, and still need mcp:read or mcp:write. See Runtime Authority for details.

Per-User Tool Visibility

Each user only sees tools from MCP servers they personally connected in their current context:

  • User A connected Fizzy only → sees fizzy__* tools
  • User B connected Linear + Fizzy → sees linear__* + fizzy__* tools
  • In org context → sees tools from servers connected within that organization
  • Personal connections never appear in org context, and vice versa

Choose Which Servers a Client Sees

By default a client of the organization-wide gateway gets every platform tool and every tool of each connected server. To give one client fewer, add the servers parameter to the URL it connects to, with the servers, or single tools, it should see separated by commas:

https://your-fabric.com/api/mcp-gateway?servers=fabric
https://your-fabric.com/api/mcp-gateway?servers=fabric,linear
https://your-fabric.com/api/mcp-gateway?servers=github_2
https://your-fabric.com/api/mcp-gateway?servers=fabric,fizzy:fizzy_get_cards,fizzy:fizzy_create_card

Each entry is one of:

  • name or name:*: every tool of that server.

  • name:tool: only that tool. tool is the name the server itself gives the tool, which is what follows <prefix>__ in the gateway's name for it: the Fizzy server's fizzy__fizzy_get_cards is fizzy:fizzy_get_cards. For fabric, use the full platform name, such as fabric:fabric_list_projects. Several name:tool entries for one server add up, and name (or name:*) alongside them means the whole server.

  • fabric names the platform tools (fabric_*).

  • Any other name is a connected server's prefix: the part before __ in its tool names. linear__list_issues belongs to linear. A server's prefix comes from its connection's name: lowercased, each run of characters other than letters and digits turned into one _, and cut to 30 characters. When two connections would share a prefix, the second gets _2, the third _3, and so on. fabric is kept for the platform tools, so a connection named "Fabric" gets fabric_2. Renaming a connection changes its prefix, so update any URL that names it.

  • Server names are case-insensitive. Tool names are case-sensitive and must be written exactly as the server gives them. Spaces around either are ignored, and repeating an entry has no effect.

  • Leave the parameter out to see every server, as before.

The selection is read once, when the client's session starts, and holds for the whole session. The tools outside it are left out of tools/list and a call to one is refused with an error, even by its exact name. After fabric_switch_organization, a selected server that the new organization does not have contributes no tools. The selection comes from the connection URL. If the gateway replaces the session because your credential now resolves to another organization, the client's next request, which carries the same URL, gets a new session with the same selection, checked again in the new organization. If the URL names a server or tool that organization lacks, the request fails with the same error as an initialize would, and so does every retry with that URL. Connect without the parameter to see every server.

If the parameter is empty, has an empty entry or an entry with nothing after : (such as fizzy:), or names a server you do not have in the organization the session runs in, the connection fails at initialize with an error that names the bad entries and lists the valid server names, rather than quietly offering fewer tools. A fabric:<tool> entry that is not a platform tool fails the same way. A <server>:<tool> entry for a connected server is checked against that server's tools: if the tool is not one of them, the error lists the server's tools, or, when it has more than 25, says how many there are and how to see them. If the server's tools cannot be discovered when the session starts, because the server is unreachable or does not answer in time and Fabric holds no earlier list of them, the entry is accepted so that an outage does not stop the connection; a tool the server turns out not to have is then simply never listed. A project's URL (/api/mcp-gateway/projects/<project-id>) has no connected servers to choose from and refuses the parameter.

The parameter narrows what one client sees and may call. It is not a permission: connecting without it shows every tool your permissions allow. It grants nothing and takes away no permission: each call to a selected tool is still checked against your scopes, project access and runtime authority, and a platform tool you leave out (such as fabric_request_authority) is simply not available on that connection.

Discovery Mode for Clients With a Tool Limit

Some clients cannot take the gateway's full tool list. Windsurf stops at 100 tools, VS Code Copilot at 128, and ChatGPT connectors limit how much text the tool definitions may take. For a client like that, add mode=discovery to the URL it connects to. Both the organization-wide URL and a project's URL accept it:

https://your-fabric.com/api/mcp-gateway?mode=discovery
https://your-fabric.com/api/mcp-gateway?mode=discovery&servers=fabric,linear
https://your-fabric.com/api/mcp-gateway/projects/<project-id>?mode=discovery

In discovery mode tools/list returns three tools instead of every tool:

ToolWhat it does
search_toolsFinds tools by keywords in their names and descriptions (query, and an optional limit, default 10, at most 25). Each match has its name, a one-line summary, its server, its read-only and destructive hints, and whether it needs runtime authority. The result also says how many tools matched in all.
get_tool_schemaReturns one tool's full definition (name): its description, input schema, hints, and whether it needs runtime authority.
call_toolRuns a tool (name, with its own arguments in arguments).

A client can also call a tool by its real name once it knows it, as in full mode.

Discovery mode changes how tools are presented, not what a connection may do. It combines with servers: search and schema cover only the selected servers and tools, and, at a project's URL, only that project's tools. They also leave out any tool your API key's or sign-in's scopes do not reach. Every call_tool call is checked exactly as a direct call to that tool is, against your scopes, the server selection, project access and runtime authority. A tool that search lists can still be refused when it is called, for example because a project is not yours to edit, because the tool checks a further scope of its own, or because authority has not been approved yet.

The mode is read once, when the client's session starts, and holds for the whole session. A later request that adds, drops or changes the parameter does not change the mode of the session it quotes. To switch modes, reconnect with a different URL. Any value other than discovery fails the connection at initialize with an error that names the accepted value.

Sessions are kept in the memory of the Fabric instance that created them. If a session is lost, for example after a restart, the client's next request starts a new one from the same URL, with the same mode and selection. Runtime authority approved for the old session is bound to that session and does not carry over, so request it again.

Runtime Authority

Connected server tools are protected by runtime authority — a Pipes-style session-scoped authorization model. This means:

  1. Credentials are persistent — your MCP server connections stay configured
  2. Runtime access is ephemeral — AI agents must request temporary permission before calling a tool that writes; read-only tools run without it
  3. Approval is human-only — agents can request authority, but only humans can approve it

The Authority Flow

Loading diagram...

Authority Tools

ToolDescription
fabric_request_authorityRequest access to providers (e.g., linear, github) with READ or WRITE level and TTL
fabric_check_authorityCheck which providers are currently authorized
fabric_revoke_authorityEnd all active authority immediately

Authority Metadata in tools/list

Connected tools include metadata saying whether a call needs authority. A read-only tool runs without a grant:

{
  "name": "linear__list_issues",
  "description": "[Linear] List issues",
  "_meta": {
    "requiresAuthority": false,
    "providerKey": "linear"
  }
}

A tool that writes needs one. providerAuthorityStatus says whether the session has any approved grant for the provider; a grant limited to other tools, to reads or to one request can still refuse the call:

{
  "name": "linear__create_issue",
  "description": "[Linear] Create a new issue",
  "_meta": {
    "requiresAuthority": true,
    "providerAuthorityStatus": "granted",
    "providerKey": "linear"
  }
}

For more details, see Runtime Authority.

Example Conversations

Cross-Platform Project Sync

"Show me the features in the Acme project, then create a Linear issue for each one that doesn't have a corresponding ticket"

The AI will:

  1. fabric_list_projects → find Acme
  2. fabric_list_documents → get feature docs
  3. fabric_request_authority for Linear (WRITE)
  4. Wait for your approval in Fabric UI
  5. linear__list_issues → compare with features
  6. linear__create_issue → create missing tickets

Research From Project Context

"Read the last two design meetings on the Acme project and tell me what we decided about rate limiting"

The AI will:

  1. fabric_list_projects → find Acme
  2. fabric_list_project_contexts with type: "MEETING_TRANSCRIPT" → list the synced transcripts
  3. fabric_get_project_context on the two most recent → read the transcript text
  4. Answer from the transcripts, paging with nextOffset if a transcript is long

This is the same material the Context tab's Download All export covers. Two things to know before you rely on it:

  • Repository code-index entries (CODE_FILE, CODE_FILE_SUMMARY) are hidden from an unfiltered listing — an indexed repo produces thousands. Pass includeCodeContexts: true or filter by that type to see them.
  • A context that pins a monitored Teams or Slack conversation carries no transcript of its own: those messages are analysed into backlog proposals rather than stored on the context. Such rows come back with contentAvailable: false and an unavailableReason saying so, rather than an empty body.

"Search the engineering library for our database migration strategy and summarize the key decisions"

The AI will:

  1. fabric_list_workspaces → find the engineering library
  2. fabric_query_workspace → semantic search for "database migration strategy"
  3. Return a summary based on the matching document chunks

Workflow Execution

"Run the weekly report workflow and send the output to #team-updates on Slack"

The AI will:

  1. fabric_list_workflows → find weekly report
  2. fabric_execute_workflow → trigger it
  3. fabric_get_workflow_execution → wait for completion
  4. fabric_request_authority for Slack (WRITE)
  5. slack__send_message → post the results

Protocol Details

Fabric provides three MCP entry points backed by the same authentication model and ui://fabric/* MCP Apps:

Entry PointURL / CommandTransportPurpose
Primary MCP GatewayPOST /api/mcp-gateway (or /api/mcp-gateway/projects/<id>)Streamable HTTP (2025-11-25)Full 169-tool platform catalog + connected 3rd-party MCP servers + OAuth 2.1 PKCE + project scoping + 24-hour idempotent durable calls
Canonical /mcp EndpointPOST /mcp (?stateless=1 supported)Streamable HTTP (2025-11-25)Short-path MCP endpoint for clients that auto-discover /mcp and .well-known/oauth-protected-resource
Stdio Bridge (@fabricorg/sdk-mcp)fabric mcp serve / npx -y @fabricorg/sdk-mcpstdio JSON-RPCLocal stdio process for stdio-only desktop clients using fabric login credentials

The HTTP gateway implements the MCP Streamable HTTP transport:

MethodEndpointPurpose
POST/api/mcp-gateway or /mcpJSON-RPC requests (initialize, tools/list, tools/call, resources/list, resources/read)
GET/api/mcp-gateway or /mcpServer info & capability discovery (health check)
DELETE/api/mcp-gatewayTerminate session

Interactive MCP Apps (ui://fabric/*)

When connected from an MCP App-capable host (Fabric Desktop, Claude Desktop, claude.ai, ChatGPT, or VS Code), tool calls return _meta.ui.resourceUri pointing to self-contained text/html;profile=mcp-app cards built with the Fabric UI Kit and A2UI v0.9.1 runtime:

  • ui://fabric/project-dashboard — Renders Fabric Projects and Fabric Artifacts & Workspaces cards for fabric_list_projects, fabric_get_project, fabric_list_frames, fabric_get_frame, fabric_list_workspaces, and fabric_list_artifacts.
  • ui://fabric/agent-delegation — Renders Tickets Assigned to You (fabric_list_features with assignedToMe: true, fabric_list_project_pm_assigned_items, fabric_list_tickets) and Agent Delegation & Subscription Credits cards with 1-click handoff to Fabric Desktop (fabricagents://) or a Remote Fabric Agents Server.
  • ui://fabric/workflow-visualizer — Renders DAG pipeline steps returned by workflow tools (fabric_list_workflows, fabric_execute_workflow); it does not invent steps when a result omits them.

Durable calls use the authenticated user, organization, credential, project binding, and selected server or MCP configuration, not tool arguments, as authorization context. Send X-Mcp-Durable: true (or _meta.durable: true) and an explicit key in X-Mcp-Idempotency-Key, _meta.idempotencyKey, or _idempotencyKey. A matching completed call within 24 hours never runs again: the gateway either replays a safe stored result or returns a non-error receipt with the execution ID and completion time. A receipt with _meta.durableExecution.resultWithheld: true omits the historical result and tells the client to use the matching get/list tool for current state. A live call with that key reports that it is in progress; a failed or expired receipt, or a RUNNING receipt older than 10 minutes, can be reclaimed. Without a key, the tool runs normally and reports that it was not deduplicated.

  • ui://fabric/genie-insights — Renders workspace RAG citations, documents, and Lakebase query results (fabric_query_workspace, fabric_search_knowledge).
  • ui://fabric/visualize — Renders custom multi-surface A2UI v0.9.1 interactive charts, tables, comparisons, and plans (fabric_visualize).

Session Management

  • Sessions are created automatically on first request
  • Session ID is returned in the Mcp-Session-Id response header
  • Sessions last 24 hours
  • Active authority sessions are completed when the gateway session ends

Authentication

MethodHeaderUse Case
Sign-in (OAuth 2.1)Authorization: Bearer fat_xxx, obtained by the clientCoding agents (recommended)
API KeyAuthorization: Bearer fab_xxx or org_xxxCI and headless clients
Session CookieAutomaticBrowser-based clients

An unauthenticated request is answered 401 with WWW-Authenticate: Bearer resource_metadata="<origin>/.well-known/oauth-protected-resource/api/mcp-gateway". That document names the authorization server (<origin>/api/auth), whose metadata is at <origin>/.well-known/oauth-authorization-server/api/auth. Clients register themselves (RFC 7591) as public clients, use PKCE S256, and request the token for the resource <origin>/api/mcp-gateway.


Next Steps