Learn

Building an intelligent Linear app assistant

Build a Linear assistant that answers questions about projects and teams and writes well-scoped issues from chat, using Linear's MCP server and Dynamiq.

Oleksii BabychMachine learning engineer4 min readUpdated

In short

This tutorial builds a project management assistant that reads your Linear workspace and creates well-described issues from a chat message. It connects a Dynamiq agent to Linear's hosted MCP server, adds session memory so follow-up requests make sense, and streams answers into a small Streamlit chat. You also limit which Linear actions the agent may take.

An intelligent Linear assistant turns a chat message like "create two tasks for next sprint" into well-scoped Linear issues, and answers questions about your projects and teams. The simplest way to build one is to connect an agent to Linear's hosted MCP server, which exposes Linear's own tools for finding, creating and updating issues, projects and comments. This tutorial does that with the open-source Dynamiq SDK, adds memory and streaming, and puts the agent behind a small chat UI.

What can the assistant do?

Once connected, the assistant can:

  • Answer questions about projects, teams and issues, such as "what's still open in the payments project?"
  • Create issues with a clear title, context and a checklist of deliverables, from a one-line request.
  • Follow up on earlier messages in the same conversation, such as "add a third task for QA".
  • Ask before guessing when a request could belong to more than one team or project.

How does the agent connect to Linear?

The Model Context Protocol (MCP) is an open standard for giving AI agents tools from other applications. Linear runs a hosted MCP server, so the agent gets Linear's actions without custom integration code.

According to Linear's MCP documentation, the server lives at https://mcp.linear.app/mcp and accepts an API key or OAuth token in an Authorization: Bearer header, as well as an interactive sign-in flow. This tutorial uses an API key; create one in Linear's settings with only the permissions the assistant needs.

Step 1: Install and configure

pip install dynamiq streamlit
export OPENAI_API_KEY="..."
export LINEAR_API_KEY="..."

Step 2: Connect to Linear's MCP server

MCPServer discovers the tools a server offers and hands them to the agent. Print their names once, then decide which ones the assistant should have.

import os

from dynamiq.nodes.tools.mcp import MCPServer, MCPStreamableHTTP

linear = MCPServer(
    name="linear",
    connection=MCPStreamableHTTP(
        url="https://mcp.linear.app/mcp",
        headers={"Authorization": f"Bearer {os.environ['LINEAR_API_KEY']}"},
    ),
)

print([tool.name for tool in linear.get_mcp_tools()])

To limit what the agent can do, pass include_tools with the tool names it may use, or exclude_tools with the ones it may not, such as anything that deletes or archives.

Step 3: Create the agent with memory and streaming

Session memory lets the agent follow a conversation, and streaming sends the answer to the UI as it is written.

from dynamiq import Workflow
from dynamiq.connections import OpenAI as OpenAIConnection
from dynamiq.flows import Flow
from dynamiq.memory import Memory
from dynamiq.memory.backends import InMemory
from dynamiq.nodes.agents import Agent
from dynamiq.nodes.llms import OpenAI
from dynamiq.types.streaming import StreamingConfig, StreamingMode

agent = Agent(
    name="PM assistant",
    llm=OpenAI(connection=OpenAIConnection(), model="gpt-4o", temperature=0.2),
    role=(
        "You help a product team manage work in Linear. Look up teams and projects before you "
        "create anything. Write issues with a clear title, the context, and a checklist of "
        "deliverables. If the team or project is ambiguous, ask before creating the issue."
    ),
    tools=[linear],
    memory=Memory(backend=InMemory()),
    streaming=StreamingConfig(enabled=True, mode=StreamingMode.FINAL),
    max_loops=12,
)

workflow = Workflow(flow=Flow(nodes=[agent]))

StreamingMode.FINAL streams only the final answer. Switch to StreamingMode.ALL if you also want to show the agent's intermediate steps, such as each Linear lookup.

Step 4: Stream answers from the workflow

Run the workflow in a background thread and read the stream as it arrives. The streaming handler stops iterating when the workflow finishes.

import threading

from dynamiq.callbacks.streaming import StreamingIteratorCallbackHandler
from dynamiq.runnables import RunnableConfig


def ask(message: str, user_id: str, session_id: str):
    handler = StreamingIteratorCallbackHandler()
    runner = threading.Thread(
        target=workflow.run,
        kwargs={
            "input_data": {"input": message, "user_id": user_id, "session_id": session_id},
            "config": RunnableConfig(callbacks=[handler]),
        },
    )
    runner.start()
    for event in handler:
        if event.event != "streaming" or not isinstance(event.data, dict):
            continue
        delta = event.data.get("choices", [{}])[0].get("delta", {}).get("content")
        if isinstance(delta, str):
            yield delta
    runner.join()

Step 5: Add a chat interface

Save the code above as assistant.py. This Streamlit app keeps one conversation per browser session and writes the streamed answer as it arrives. Start it with streamlit run app.py.

import uuid

import streamlit as st

from assistant import ask

st.title("Linear assistant")

if "session_id" not in st.session_state:
    st.session_state.session_id = str(uuid.uuid4())
    st.session_state.messages = []

for message in st.session_state.messages:
    with st.chat_message(message["role"]):
        st.markdown(message["content"])

if prompt := st.chat_input("Ask about a project or describe an issue"):
    st.session_state.messages.append({"role": "user", "content": prompt})
    with st.chat_message("user"):
        st.markdown(prompt)
    with st.chat_message("assistant"):
        reply = st.write_stream(ask(prompt, user_id="pm-team", session_id=st.session_state.session_id))
    st.session_state.messages.append({"role": "assistant", "content": reply})

Try "Show me our teams and active projects", then "Create an issue in the data team's project for an exploratory analysis of churn, with deliverables". Open Linear to see the issue the agent wrote.

How do you keep the assistant from doing too much?

An assistant that can write to your project tracker needs the same care as a new team member with edit access:

  • Scope the credentials. Use an API key with only the permissions the assistant needs.
  • Scope the tools. Use include_tools or exclude_tools so the agent cannot delete or archive anything.
  • Require approval for writes. On the Dynamiq platform, an approval can pause the step that creates an issue, so a person can edit its fields before it runs.
  • Review what happened. Every run is traced, including each Linear call the agent made.

Can you do this without writing code?

Yes. AI Coworker connects to Linear as one of its app connectors and works in the browser and in Slack, Microsoft Teams and Telegram. A team can ask it for a status summary in a Slack thread or have it draft issues from meeting notes, without building anything.

Linear is one of the 2,100+ app integrations available to agents, alongside Jira, Asana and other trackers; see the integrations page.

FAQ

Can AI create Linear issues automatically?

Yes. An agent connected to Linear's MCP server can create issues with titles, descriptions and deliverables from a plain-language request. Keep an approval step or a narrow set of tools if you want a person to confirm each change.

What is the Linear MCP server?

It is a hosted server from Linear that implements the Model Context Protocol. It gives AI agents tools for finding, creating and updating Linear objects such as issues, projects and comments, authenticated with OAuth or an API key.

How do you stop the assistant from changing things it shouldn't?

Combine a restricted API key, a limited tool list with include_tools or exclude_tools, clear instructions in the agent's role, and an approval step before any write. Traces show exactly what the agent did afterward.

Does the assistant remember earlier messages?

Within a conversation, yes: session memory is scoped by user and session, so follow-ups like "add one more task" work. For preferences that should persist across conversations, add long-term memory, as shown in our guide to conversational agents with memory.

Can the same approach work with Jira or other trackers?

Yes. Point the agent at another MCP server or give it tools from the platform's app integrations, which include Jira and other project management tools. The agent code stays the same.

Put this into practice.

See an agent built for your workflow, running in your environment, with our engineers.